mirror of
https://ghfast.top/https://github.com/aeroxw/easy_tdx_max.git
synced 2026-09-12 14:34:18 +08:00
fix: 一键寻优所有策略补齐 35 个新策略预设网格(STRATEGY_PRESETS 19→54,网格点 174→328)+ 注册表↔预设一致性回归测试
This commit is contained in:
@@ -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],
|
||||
}, # 9(n1<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],
|
||||
}, # 3(n1 用默认 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],
|
||||
}, # 3(m1 用默认 26)
|
||||
"zhuoyao_trend": {
|
||||
"n2": [40, 60, 90],
|
||||
"n3": [10, 20],
|
||||
}, # 6(n3<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],
|
||||
}, # 3(fast/slow 用默认 2/30)
|
||||
"hma_cross": {
|
||||
"fast": [10, 16],
|
||||
"slow": [30, 50],
|
||||
}, # 4
|
||||
"chandelier": {
|
||||
"n": [15, 22, 30],
|
||||
"k": [2.5, 3.0],
|
||||
}, # 6(m 用默认 22)
|
||||
"ichimoku_cross": {
|
||||
"p1": [9, 20],
|
||||
"p2": [26, 40],
|
||||
}, # 4(p1<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],
|
||||
}, # 4(s 用默认 13)
|
||||
"fisher_cross": {
|
||||
"n": [5, 9, 13],
|
||||
}, # 3
|
||||
"squeeze_breakout": {
|
||||
"kc": [1.2, 1.5, 2.0],
|
||||
}, # 3(n=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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -166,3 +166,52 @@ class TestParamGridOptimizer:
|
||||
)
|
||||
with pytest.raises(KeyError):
|
||||
opt.run()
|
||||
|
||||
|
||||
class TestStrategyPresets:
|
||||
"""预设网格与策略注册表的一致性。
|
||||
|
||||
「一键寻优所有策略」只遍历 STRATEGY_PRESETS(backtest.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:
|
||||
"""单策略笛卡尔积 ≤ 200(ParamGridOptimizer.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} 点超上限"
|
||||
|
||||
Reference in New Issue
Block a user