216 lines
7.8 KiB
Python
216 lines
7.8 KiB
Python
"""Central registry for strategy identity and display metadata."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass, field
|
||
|
||
|
||
MAIN_COMPOSITE_STRATEGY = "main_composite_v1"
|
||
BOX_RETEST_1H_STRATEGY = "box_retest_1h_v1"
|
||
BOX_RETEST_4H_STRATEGY = "box_retest_4h_v1"
|
||
VOLUME_IGNITION_1H_STRATEGY = "volume_ignition_1h_v1"
|
||
COMPRESSION_BREAKOUT_4H_STRATEGY = "compression_breakout_4h_v1"
|
||
INTRADAY_MOMENTUM_15M_STRATEGY = "intraday_momentum_15m_v1"
|
||
BREAKDOWN_RETEST_SHORT_1H_STRATEGY = "breakdown_retest_short_1h_v1"
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class StrategyDefinition:
|
||
strategy_code: str
|
||
strategy_name: str
|
||
description: str = ""
|
||
mode: str = "paper_only"
|
||
status: str = "active"
|
||
entry_gate_config: dict = field(default_factory=dict)
|
||
paper_config: dict = field(default_factory=dict)
|
||
|
||
|
||
STRATEGY_DEFINITIONS: dict[str, StrategyDefinition] = {
|
||
MAIN_COMPOSITE_STRATEGY: StrategyDefinition(
|
||
strategy_code=MAIN_COMPOSITE_STRATEGY,
|
||
strategy_name="综合确认策略",
|
||
description="迁移期兼容综合策略,承载现有综合筛选与确认逻辑;它与其他策略平等运行。",
|
||
mode="paper_enabled",
|
||
),
|
||
BOX_RETEST_1H_STRATEGY: StrategyDefinition(
|
||
strategy_code=BOX_RETEST_1H_STRATEGY,
|
||
strategy_name="1H箱体突破回踩",
|
||
description="小时级底部箱体突破后回踩箱体上沿或EMA承接的早期结构策略。",
|
||
mode="paper_only",
|
||
entry_gate_config={
|
||
"min_entry_score_buy_now": 1,
|
||
"min_entry_score_wait_pullback": 0,
|
||
"min_rr_buy_now": 1.2,
|
||
"max_wait_pullback_deviation_pct": 20,
|
||
"breakout_distance_wait_pct": 25,
|
||
"gain_24h_wait_pct": 12,
|
||
},
|
||
paper_config={
|
||
"entry_min_rr": 1.5,
|
||
"order_min_rr": 1.5,
|
||
"order_min_distance_to_entry_pct": 0,
|
||
"order_require_current_trigger": False,
|
||
"dynamic_leverage_enabled": True,
|
||
"dynamic_leverage_min": 3,
|
||
},
|
||
),
|
||
BOX_RETEST_4H_STRATEGY: StrategyDefinition(
|
||
strategy_code=BOX_RETEST_4H_STRATEGY,
|
||
strategy_name="4H箱体突破回踩",
|
||
description="底部箱体突破后回踩箱体上沿或EMA承接的结构策略。",
|
||
mode="paper_only",
|
||
entry_gate_config={
|
||
"min_entry_score_buy_now": 1,
|
||
"min_entry_score_wait_pullback": 0,
|
||
"min_rr_buy_now": 1.2,
|
||
"max_wait_pullback_deviation_pct": 20,
|
||
"breakout_distance_wait_pct": 25,
|
||
"gain_24h_wait_pct": 12,
|
||
},
|
||
paper_config={
|
||
"entry_min_rr": 1.5,
|
||
"order_min_rr": 1.5,
|
||
"order_min_distance_to_entry_pct": 0,
|
||
"order_require_current_trigger": False,
|
||
"dynamic_leverage_enabled": True,
|
||
"dynamic_leverage_min": 3,
|
||
},
|
||
),
|
||
VOLUME_IGNITION_1H_STRATEGY: StrategyDefinition(
|
||
strategy_code=VOLUME_IGNITION_1H_STRATEGY,
|
||
strategy_name="1H放量突破启动",
|
||
description="1H量价齐飞或连续放量后的启动策略,适合捕捉日内到3天的第一段加速。",
|
||
mode="paper_only",
|
||
entry_gate_config={
|
||
"min_entry_score_buy_now": 2,
|
||
"min_entry_score_wait_pullback": 1,
|
||
"min_rr_buy_now": 1.25,
|
||
"breakout_distance_wait_pct": 12,
|
||
"gain_24h_wait_pct": 10,
|
||
},
|
||
paper_config={
|
||
"entry_min_rr": 1.5,
|
||
"order_min_rr": 1.5,
|
||
"order_min_distance_to_entry_pct": 0,
|
||
"order_require_current_trigger": True,
|
||
"dynamic_leverage_enabled": True,
|
||
"dynamic_leverage_min": 3,
|
||
},
|
||
),
|
||
COMPRESSION_BREAKOUT_4H_STRATEGY: StrategyDefinition(
|
||
strategy_code=COMPRESSION_BREAKOUT_4H_STRATEGY,
|
||
strategy_name="4H压缩蓄力突破",
|
||
description="4H静K蓄力、底部抬高或压缩放量后的突破策略,偏向捕捉1周以内主升前段。",
|
||
mode="paper_only",
|
||
entry_gate_config={
|
||
"min_entry_score_buy_now": 2,
|
||
"min_entry_score_wait_pullback": 0,
|
||
"min_rr_buy_now": 1.3,
|
||
"max_wait_pullback_deviation_pct": 18,
|
||
"breakout_distance_wait_pct": 18,
|
||
"gain_24h_wait_pct": 12,
|
||
},
|
||
paper_config={
|
||
"entry_min_rr": 1.6,
|
||
"order_min_rr": 1.6,
|
||
"order_min_distance_to_entry_pct": 0,
|
||
"order_require_current_trigger": False,
|
||
"dynamic_leverage_enabled": True,
|
||
"dynamic_leverage_min": 3,
|
||
},
|
||
),
|
||
INTRADAY_MOMENTUM_15M_STRATEGY: StrategyDefinition(
|
||
strategy_code=INTRADAY_MOMENTUM_15M_STRATEGY,
|
||
strategy_name="15m日内动量延续",
|
||
description="短周期放量突破与1H背景共振的日内动量策略,只做当前触发,不做纯观察追高。",
|
||
mode="paper_only",
|
||
entry_gate_config={
|
||
"min_entry_score_buy_now": 3,
|
||
"min_entry_score_wait_pullback": 2,
|
||
"min_rr_buy_now": 1.4,
|
||
"breakout_distance_wait_pct": 8,
|
||
"gain_24h_wait_pct": 8,
|
||
},
|
||
paper_config={
|
||
"entry_min_rr": 1.6,
|
||
"order_min_rr": 1.6,
|
||
"order_min_distance_to_entry_pct": 0,
|
||
"order_require_current_trigger": True,
|
||
"dynamic_leverage_enabled": True,
|
||
"dynamic_leverage_min": 3,
|
||
},
|
||
),
|
||
BREAKDOWN_RETEST_SHORT_1H_STRATEGY: StrategyDefinition(
|
||
strategy_code=BREAKDOWN_RETEST_SHORT_1H_STRATEGY,
|
||
strategy_name="1H破位反抽做空",
|
||
description="箱体或关键均线破位后反抽失败的空头策略;只用于独立空头样本,不与多头突破策略共享入场门槛。",
|
||
mode="paper_only",
|
||
entry_gate_config={
|
||
"direction": "short",
|
||
"min_entry_score_buy_now": 2,
|
||
"min_entry_score_wait_pullback": 1,
|
||
"min_rr_buy_now": 1.5,
|
||
"breakdown_distance_wait_pct": 10,
|
||
"max_retest_deviation_pct": 8,
|
||
},
|
||
paper_config={
|
||
"entry_min_rr": 1.8,
|
||
"order_min_rr": 1.8,
|
||
"order_min_distance_to_entry_pct": 0,
|
||
"order_require_current_trigger": True,
|
||
"dynamic_leverage_enabled": True,
|
||
"dynamic_leverage_min": 2,
|
||
},
|
||
),
|
||
}
|
||
|
||
|
||
def normalize_strategy_code(strategy_code: str | None) -> str:
|
||
code = str(strategy_code or "").strip()
|
||
return code or MAIN_COMPOSITE_STRATEGY
|
||
|
||
|
||
def strategy_definition(strategy_code: str | None) -> StrategyDefinition:
|
||
code = normalize_strategy_code(strategy_code)
|
||
return STRATEGY_DEFINITIONS.get(
|
||
code,
|
||
StrategyDefinition(
|
||
strategy_code=code,
|
||
strategy_name=code,
|
||
description="未注册策略,请补充 strategy_registry。",
|
||
status="unknown",
|
||
),
|
||
)
|
||
|
||
|
||
def strategy_label(strategy_code: str | None) -> str:
|
||
return strategy_definition(strategy_code).strategy_name
|
||
|
||
|
||
def strategy_entry_gate_config(strategy_code: str | None) -> dict:
|
||
return dict(strategy_definition(strategy_code).entry_gate_config or {})
|
||
|
||
|
||
def strategy_paper_config(strategy_code: str | None) -> dict:
|
||
return dict(strategy_definition(strategy_code).paper_config or {})
|
||
|
||
|
||
def registered_strategy_codes() -> list[str]:
|
||
return list(STRATEGY_DEFINITIONS.keys())
|
||
|
||
|
||
def strategy_catalog_seed_rows(strategy_version: str = "") -> list[dict]:
|
||
rows = []
|
||
for item in STRATEGY_DEFINITIONS.values():
|
||
rows.append(
|
||
{
|
||
"strategy_code": item.strategy_code,
|
||
"strategy_name": item.strategy_name,
|
||
"strategy_version": strategy_version or "",
|
||
"status": item.status,
|
||
"mode": item.mode,
|
||
"description": item.description,
|
||
}
|
||
)
|
||
return rows
|