"""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