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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user