mirror of
https://github.com/shy3130/tick-stock-panel.git
synced 2026-11-02 10:26:13 +00:00
参数排名从单窗样本内得分改为 K 段折外稳健分 R = 0.6×中位 + 0.4×最差 (设计: docs/robust-optimizer-plan.md), 四阶段全部落地: - guards 共享护栏: 主目标白名单 + 最小交易数门槛 (fail-closed, 缺交易数 按不达标处理), 两模式一处实现 - robust_optimizer: 等分切窗 (2-6 段, 每段≥14天) / 稳健分 / 冠军收敛诊断 (unanimous/majority/scattered) / Top-20 全窗 IS 细化与退化率 / 高原判据 (邻域得分衰减, 零额外回测); worker 接线 robust_optimize 任务 - 滚动样本外检验补强: 每折 OOS 最小交易数门槛 (无效折透明跳过), 前端折预览 / 参数漂移轨迹 / 采用最新折参数 - 前端: 冠军卡 (收敛/高原徽章/乐观偏差) + K 段排名表 + 验证窗预览 + 应用参数闭环 (POST /strategies/config, 可逆); SSE 重连与跨设备接回 - P4 摒弃旧路径: 删 /optimize/stream 与 /optimize/cancel 端点及 worker optimize 任务类型; 白名单全面生效 (optimizer.VALID_OBJECTIVES 收敛到 guards; walkforward 端点校验退化目标 400) - 附带修复: 叠加条件×矩阵路径 SignalMatrix 只读违规 (np.where 产物 可写), optimizer_trial 轻量统计恒保留 n_trades 实测: 126 组合全市场网格 1.71× 旧版耗时 (视图复用优化自 2.01×; 差额 为引擎层每 run 固定开销, 详见方案文档第九节); 全量回归 3131 通过。 api.ts 同时带入稳健优化折预览客户端与声效语音包 API 客户端 (语音包功能随后续提交落地界面)。 Signed-off-by: shy3130 <shy3130@qq.com>
43 lines
1.7 KiB
Python
43 lines
1.7 KiB
Python
"""优化/验证任务共享护栏: 主目标白名单与最小交易数门槛。
|
|
|
|
一处定义, 稳健优化 (robust_optimizer) 与滚动样本外检验 (walkforward) 共用;
|
|
optimizer.py 的 VALID_OBJECTIVES 已收敛到此 (P4)。设计见 docs/robust-optimizer-plan.md 第四节。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
# 可作主目标的指标: 方向语义明确、跨参数组可比、不随交易数退化。
|
|
# max_drawdown / mc_maxdd_* 为负值, 最大化带符号值 = 回撤越小越好。
|
|
PRIMARY_OBJECTIVES: frozenset[str] = frozenset({
|
|
"sortino", "sharpe", "calmar",
|
|
"annual_return", "total_return", "profit_factor",
|
|
"max_drawdown", "mc_maxdd_p50", "mc_maxdd_p95",
|
|
"avg_pnl", "median_pnl",
|
|
})
|
|
|
|
# 退化目标: 交易数少时可被运气推到极端 (3 笔全胜 = win_rate 100%), 只作展示列
|
|
# 或约束条件, 不得作主排名目标。
|
|
DEGENERATE_OBJECTIVES: frozenset[str] = frozenset({
|
|
"win_rate", "avg_holding_days", "n_trades",
|
|
})
|
|
|
|
|
|
def validate_primary_objective(objective: str) -> None:
|
|
"""主目标必须在白名单内, 否则抛 ValueError (端点转 400)。"""
|
|
if objective not in PRIMARY_OBJECTIVES:
|
|
raise ValueError(
|
|
f"'{objective}' 不适合作稳健优化的主目标 (交易数少时会退化); "
|
|
f"可选: {sorted(PRIMARY_OBJECTIVES)}"
|
|
)
|
|
|
|
|
|
def trades_ok(stats: dict, min_trades: int) -> bool:
|
|
"""最小交易数门槛: stats 的 n_trades 达标才有效; min_trades<=0 表示关闭。
|
|
|
|
缺失 n_trades 按不达标处理 (fail-closed: 宁可误杀也不让无交易组合登顶)。
|
|
"""
|
|
if min_trades is None or min_trades <= 0:
|
|
return True
|
|
n = stats.get("n_trades")
|
|
return isinstance(n, (int, float)) and n >= min_trades
|