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
This commit is contained in:
LEGSTECH Optimizer
2026-04-25 11:39:17 +00:00
parent e5dd9550b7
commit 6caafdb794
31 changed files with 7546 additions and 1113 deletions
+48
View File
@@ -30,6 +30,8 @@ from scoring.composite import CompositeScorer
from mutation.engine import MutationEngine
from validation.gate import ValidationGate
from reports.writer import ReportWriter
from analysis.ai_reasoner import AIReasoner
from analysis.ai_reasoner_config import load_api_key
import pandas as pd
@@ -70,6 +72,11 @@ class OptimizerLoop:
self.run_start_ts: Optional[float] = None
self.session_tested_deltas: list[dict] = [] # dedup within this session only
# AI Reasoning Layer
api_key = load_api_key(config_path)
self.ai_reasoner = AIReasoner(api_key=api_key)
self._run_history: list[dict] = [] # accumulates across iterations for AI context
with open(config_path) as f:
self.cfg = yaml.safe_load(f)
@@ -143,6 +150,26 @@ class OptimizerLoop:
# Write baseline report
findings = self._run_analysis(baseline_id, baseline_trades, baseline_metrics,
analyzers, store)
# AI Reasoning — baseline
self._emit("log", {"level": "info", "msg": "🤖 AI Reasoner analyzing baseline..."})
ai_insight = self.ai_reasoner.analyze(
findings=findings,
metrics=baseline_metrics,
run_history=self._run_history,
current_params=default_params,
)
self._run_history.append({
"run_id": baseline_id,
"score": round(baseline_metrics.composite_score, 4),
"calmar": round(baseline_metrics.calmar_ratio, 4),
"pf": round(baseline_metrics.profit_factor, 4),
"phase": "baseline",
"params": default_params,
})
self._emit("ai_insight", ai_insight.to_dict())
self._emit("log", {"level": "info", "msg": f"🤖 AI: {ai_insight.headline}"})
writer.write(baseline_id, baseline_metrics, baseline_trades, findings, default_params)
self.best_score = baseline_metrics.composite_score
@@ -184,6 +211,17 @@ class OptimizerLoop:
self._emit("log", {"level": "warn", "msg": "No actionable findings. Stopping."})
break
# AI Reasoning — per iteration
self._emit("log", {"level": "info", "msg": f"🤖 AI Reasoner analyzing iteration {self.iteration}..."})
ai_insight = self.ai_reasoner.analyze(
findings=findings,
metrics=current_metrics,
run_history=self._run_history,
current_params=current_params,
)
self._emit("ai_insight", ai_insight.to_dict())
self._emit("log", {"level": "info", "msg": f"🤖 AI: {ai_insight.headline}"})
# Mutation proposals — only dedup within this session
hypotheses = mutator.propose(
findings=findings,
@@ -345,6 +383,16 @@ class OptimizerLoop:
else:
no_improve_count += 1
# Track run history for AI context
self._run_history.append({
"run_id": iteration_best.run_id,
"score": round(iteration_best.composite_score, 4),
"calmar": round(iteration_best.calmar_ratio, 4),
"pf": round(iteration_best.profit_factor, 4),
"phase": "explore",
"params": iteration_best_params,
})
# Update score chart
self.score_history.append({
"iteration": self.iteration,