""" 因子注册表。 通过名称获取因子实例,方便回测和策略配置时引用。 """ from factors.base import BaseFactor from factors.technical.momentum import MomentumFactor from factors.technical.rsi import RSIFactor from factors.technical.macd import MACDFactor from factors.technical.volume import VolumeFactor, VolumeChangeFactor from factors.technical.bollinger import BollingerFactor, BollingerWidthFactor from factors.technical.atr import ATRFactor, ATRRatioFactor from factors.technical.ma_cross import MACrossFactor, MADeviationFactor from factors.technical.volatility import VolatilityFactor, DownsideVolatilityFactor from factors.technical.turnover import TurnoverFactor, TurnoverChangeFactor from factors.technical.amplitude import AmplitudeFactor from factors.fundamental.roe import ROEFactor from factors.fundamental.pe_pb import PEFactor, PBFactor, EPFactor from factors.sentiment.sentiment_factor import ( NewsSentimentFactor, SentimentMomentumFactor, SentimentConfidenceFactor, ) # ── 内置因子工厂函数 ────────────────────────────────────── _BUILTIN_FACTORIES: dict[str, callable] = { # type: ignore # 动量 "momentum_5": lambda: MomentumFactor(period=5), "momentum_10": lambda: MomentumFactor(period=10), "momentum_20": lambda: MomentumFactor(period=20), "momentum_60": lambda: MomentumFactor(period=60), # RSI "rsi_7": lambda: RSIFactor(period=7), "rsi_14": lambda: RSIFactor(period=14), # MACD "macd": lambda: MACDFactor(), "macd_5_35_5": lambda: MACDFactor(fast=5, slow=35, signal=5), # 量价 "vol_ratio_5": lambda: VolumeFactor(period=5), "vol_ratio_20": lambda: VolumeFactor(period=20), "vol_chg_5": lambda: VolumeChangeFactor(period=5), # 布林 "boll": lambda: BollingerFactor(), "boll_width": lambda: BollingerWidthFactor(), # ATR "atr_14": lambda: ATRFactor(period=14), "atr_ratio_14": lambda: ATRRatioFactor(period=14), # 均线 "ma_cross_5_20": lambda: MACrossFactor(fast=5, slow=20), "ma_cross_10_60": lambda: MACrossFactor(fast=10, slow=60), "ma_dev_20": lambda: MADeviationFactor(period=20), "ma_dev_60": lambda: MADeviationFactor(period=60), # 波动率 "volatility_20": lambda: VolatilityFactor(period=20), "volatility_60": lambda: VolatilityFactor(period=60), "down_vol_20": lambda: DownsideVolatilityFactor(period=20), # 换手率 "turnover_5": lambda: TurnoverFactor(period=5), "turnover_chg_5": lambda: TurnoverChangeFactor(period=5), # 振幅 "amplitude_5": lambda: AmplitudeFactor(period=5), "amplitude_20": lambda: AmplitudeFactor(period=20), # 基本面 "roe": lambda: ROEFactor(), "pe": lambda: PEFactor(), "pb": lambda: PBFactor(), "ep": lambda: EPFactor(), # 情绪 "news_sent_5": lambda: NewsSentimentFactor(window=5), "news_sent_20": lambda: NewsSentimentFactor(window=20), "news_conf_5": lambda: SentimentConfidenceFactor(window=5), "sent_delta_5": lambda: SentimentMomentumFactor(period=5), } # ── 分类映射 ────────────────────────────────────────────── FACTOR_CATEGORIES: dict[str, list[str]] = { "动量": ["momentum_5", "momentum_10", "momentum_20", "momentum_60"], "RSI": ["rsi_7", "rsi_14"], "MACD": ["macd", "macd_5_35_5"], "量价": ["vol_ratio_5", "vol_ratio_20", "vol_chg_5"], "布林": ["boll", "boll_width"], "ATR": ["atr_14", "atr_ratio_14"], "均线": ["ma_cross_5_20", "ma_cross_10_60", "ma_dev_20", "ma_dev_60"], "波动率": ["volatility_20", "volatility_60", "down_vol_20"], "换手率": ["turnover_5", "turnover_chg_5"], "振幅": ["amplitude_5", "amplitude_20"], "基本面": ["roe", "pe", "pb", "ep"], "情绪": ["news_sent_5", "news_sent_20", "news_conf_5", "sent_delta_5"], } def get_factor(name: str, **overrides) -> BaseFactor: """按名称获取因子实例。 参数: name: 因子名称(如 'momentum_20') **overrides: 覆盖默认参数 返回: BaseFactor 实例 说明: 返回实例的 .name 恒等于注册键 name,即使构造器默认生成的 .name 与注册键不同(如 boll 的构造器默认 .name='boll_20')—— 注册键是列名的唯一事实源,避免 FactorEngine.compute 的列名漂移。 """ if name not in _BUILTIN_FACTORIES: raise KeyError(f"未知因子: '{name}'。可用: {list(_BUILTIN_FACTORIES)}") factor = _BUILTIN_FACTORIES[name]() if overrides: for k, v in overrides.items(): if hasattr(factor, k): setattr(factor, k, v) # 无论是否覆盖参数,都强制 .name = 注册键,保证与分类/策略的引用一致 if hasattr(factor, "name"): factor.name = name return factor def list_factors(category: str | None = None) -> list[str]: """列出所有可用因子名称。""" if category and category in FACTOR_CATEGORIES: return FACTOR_CATEGORIES[category] return list(_BUILTIN_FACTORIES) def list_categories() -> list[str]: """列出所有因子分类。""" return list(FACTOR_CATEGORIES)