phase 7-8 完成 + warmup 修复 + 产物结构化重组

主要内容:
- Phase 8 PROMOTE: finalist #1 (trial #324) registry 条目,自动生成
- Optuna objective warmup bug 修复 (shared/optimizer/objective.py)
- studies/ 目录按用途重组为 optuna/ + finalists/ + features/ 三层
- reports/ 加入 Optuna 中文 dashboard (5 主图 + 18 slice + 15 contour)
- 新增 PROJECT_GUIDE.md 项目说明文档
- 新增 build_registry_entry.py / build_optuna_dashboard.py / build_feature_datasets.py
- .gitignore: 允许提交 studies/*.db (Optuna DB) 和 reports/*.html (MT5 + dashboard)
This commit is contained in:
2026-06-27 00:28:07 +08:00
parent 0dcbfe0781
commit 63a829cc46
45 changed files with 7240 additions and 9 deletions
+12 -1
View File
@@ -198,7 +198,18 @@ class ScalperEngine:
sl = sl_prices[i] if not np.isnan(sl_prices[i]) else 0.0
tp = tp_prices[i] if not np.isnan(tp_prices[i]) else 0.0
lots = self._calc_lots(cfg, instrument, sl, equity)
# _calc_lots expects the SL *distance* (price units), not the
# SL price level. signals.py sets sl_prices[i] = close[i] ±
# sl_dist[i] (where sl_dist[i] = InpAtrSLMult × ATR[i]), so
# |close[i] - sl_prices[i]| recovers exactly sl_dist[i] — the
# same distance MT5 uses for sizing (it does NOT include the
# gap between signal-bar close and next-bar fill). Using
# fill_price here instead made sl_distance vary with the
# open-gap, sometimes bigger, sometimes smaller than MT5's
# value, which made lots inconsistent and the equity curve
# diverge exponentially from MT5 under risk% compounding.
sl_distance = abs(closes[i] - sl) if sl > 0 else 0.0
lots = self._calc_lots(cfg, instrument, sl_distance, equity)
if lots > 0:
open_pos = Position(
direction=direction,