fix: 一键寻优所有策略补齐 35 个新策略预设网格(STRATEGY_PRESETS 19→54,网格点 174→328)+ 注册表↔预设一致性回归测试

This commit is contained in:
Justin Gu
2026-09-03 03:27:04 +08:00
parent 62e80d892e
commit e866e82299
2 changed files with 172 additions and 0 deletions
+123
View File
@@ -98,6 +98,129 @@ STRATEGY_PRESETS: dict[str, dict[str, list[Any]]] = {
# capital 仅作粗档扫描(1千万/1亿/10亿股),覆盖小盘→大盘
"capital": [1e7, 1e8, 1e9, 1e10],
}, # 4
# ── V1.30.2 存量指标补齐 ────────────────────────────────────────────────
"psy_reversal": {
"n": [12, 20],
"oversold": [20, 25, 30],
}, # 6
"mtm_cross": {
"n": [6, 12, 24],
}, # 3
"roc_zero": {
"n": [6, 12, 24],
}, # 3
"expma_cross": {
"n1": [5, 10, 12],
"n2": [26, 50, 60],
}, # 9n1<n2 全部有效)
"dfma_cross": {
"n1": [5, 10],
"n2": [30, 50],
}, # 4
"cr_reversal": {
"n": [20, 26],
"oversold": [30, 40],
}, # 4
"xsii_breakout": {
"n": [80, 102, 120],
}, # 3
"obv_cross": {
"m": [10, 20, 30, 60],
}, # 4
"vr_reversal": {
"m1": [20, 26],
"oversold": [40, 50],
}, # 4
"mass_cross": {
"n2": [20, 25, 30],
}, # 3n1 用默认 9
"mfi_reversal": {
"n": [14, 20],
"oversold": [15, 20],
}, # 4
"brar_reversal": {
"m1": [26],
"oversold": [30, 40, 50],
}, # 3
"asi_cross": {
"m2": [7, 10, 14],
}, # 3m1 用默认 26
"zhuoyao_trend": {
"n2": [40, 60, 90],
"n3": [10, 20],
}, # 6n3<n2 全部有效)
"bias_signal_cross": {
"p": [5, 10],
"m": [20, 30, 60],
}, # 6
"sar_follow": {
"af_step": [0.01, 0.02, 0.03],
}, # 3
"vwap_cross": {
"n": [10, 20, 30],
}, # 3
"aroon_cross": {
"n": [14, 21, 25],
}, # 3
"fk_reversal": {}, # 无参数策略:单点(默认参数)
# ── V1.30.2 新指标首发 ──────────────────────────────────────────────────
"supertrend": {
"n": [7, 10, 14],
"m": [2.0, 3.0, 4.0],
}, # 9
"kama_cross": {
"n": [10, 20, 30],
}, # 3fast/slow 用默认 2/30
"hma_cross": {
"fast": [10, 16],
"slow": [30, 50],
}, # 4
"chandelier": {
"n": [15, 22, 30],
"k": [2.5, 3.0],
}, # 6m 用默认 22
"ichimoku_cross": {
"p1": [9, 20],
"p2": [26, 40],
}, # 4p1<p2<p3=52 全部有效)
"uos_reversal": {
"oversold": [25, 30, 35],
}, # 3(周期用默认 7/14/28
"cmo_reversal": {
"n": [14, 20],
"threshold": [40.0, 50.0, 60.0],
}, # 6
"tsi_cross": {
"r": [13, 25],
"m": [7, 13],
}, # 4s 用默认 13
"fisher_cross": {
"n": [5, 9, 13],
}, # 3
"squeeze_breakout": {
"kc": [1.2, 1.5, 2.0],
}, # 3n=20/bb=2.0 用默认)
"chop_trend": {
"n_ma": [20, 30],
"trend_th": [35.0, 38.2],
}, # 4
"ad_cross": {
"m": [10, 20, 30, 60],
}, # 4
"cmf_zero": {
"n": [14, 20, 30],
}, # 3
"efi_zero": {
"n": [10, 13, 20],
}, # 3
"bbp_reversal": {
"n": [10, 20],
"p": [1.5, 2.0],
}, # 4
"bbw_squeeze": {
"n": [20, 30],
"n_ma": [20, 30],
}, # 4
}
+49
View File
@@ -166,3 +166,52 @@ class TestParamGridOptimizer:
)
with pytest.raises(KeyError):
opt.run()
class TestStrategyPresets:
"""预设网格与策略注册表的一致性。
「一键寻优所有策略」只遍历 STRATEGY_PRESETSbacktest.py optimize-all),
未登记的策略会被静默跳过——v1.30.2 曾因此只寻优 19/54 个策略。
这里双向锁定:每个已注册策略必须有预设,且网格合法。
"""
def test_every_registered_strategy_has_preset(self) -> None:
"""注册表与 STRATEGY_PRESETS 键集一一对应(双向:不多不少)。"""
from easy_tdx.backtest.strategies import (
builtin, # noqa: F401 # 触发注册
get_registry,
)
from easy_tdx.backtest.strategies.presets import STRATEGY_PRESETS
names = set(get_registry().names())
missing = names - set(STRATEGY_PRESETS)
extra = set(STRATEGY_PRESETS) - names
assert not missing, f"这些策略无预设网格,会被一键寻优静默跳过: {sorted(missing)}"
assert not extra, f"这些预设指向未注册的策略: {sorted(extra)}"
def test_preset_values_within_param_bounds(self) -> None:
"""预设取值必须在参数 schema 边界内(否则寻优端点 422)。"""
from easy_tdx.backtest.strategies import (
builtin, # noqa: F401 # 触发注册
get_registry,
)
from easy_tdx.backtest.strategies.presets import STRATEGY_PRESETS
registry = get_registry()
for name, grid in STRATEGY_PRESETS.items():
params = {p.name: p for p in registry.get(name).params}
for pname, values in grid.items():
assert pname in params, f"{name}: 预设参数 {pname} 不在 schema 中"
for v in values:
params[pname].validate(v) # 越界抛 ValueError
def test_preset_grid_size_within_limit(self) -> None:
"""单策略笛卡尔积 ≤ 200ParamGridOptimizer.MAX_GRID_POINTS)。"""
import math
from easy_tdx.backtest.strategies.presets import STRATEGY_PRESETS
for name, grid in STRATEGY_PRESETS.items():
size = math.prod(len(v) for v in grid.values()) if grid else 1
assert size <= 200, f"{name}: 预设网格 {size} 点超上限"