feat(factors): 集成 metadata 模块,支持按名称注册因子
- 新增 add_factor_by_name() 方法,从 metadata 查询 DSL 表达式并注册 - FactorEngine 支持可选的 metadata_path 参数初始化 - 将 regression.ipynb 和 learn_to_rank.ipynb 转换为 Python 脚本 - 新增 test_factor_engine_metadata.py 测试文件
This commit is contained in:
@@ -16,6 +16,7 @@ import polars as pl
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.factors.registry import FunctionRegistry
|
||||
from src.factors.metadata import FactorManager
|
||||
|
||||
from src.factors.dsl import (
|
||||
Node,
|
||||
@@ -57,6 +58,7 @@ class FactorEngine:
|
||||
data_source: Optional[Dict[str, pl.DataFrame]] = None,
|
||||
max_workers: int = 4,
|
||||
registry: Optional["FunctionRegistry"] = None,
|
||||
metadata_path: Optional[str] = None,
|
||||
) -> None:
|
||||
"""初始化因子引擎。
|
||||
|
||||
@@ -64,6 +66,7 @@ class FactorEngine:
|
||||
data_source: 内存数据源,为 None 时使用数据库连接
|
||||
max_workers: 并行计算的最大工作线程数
|
||||
registry: 函数注册表,None 时创建独立实例
|
||||
metadata_path: 因子元数据文件路径,为 None 时不启用 metadata 功能
|
||||
"""
|
||||
from src.factors.registry import FunctionRegistry
|
||||
from src.factors.parser import FormulaParser
|
||||
@@ -78,6 +81,13 @@ class FactorEngine:
|
||||
self._registry = registry if registry is not None else FunctionRegistry()
|
||||
self._parser = FormulaParser(self._registry)
|
||||
|
||||
# 初始化 metadata 管理器(可选)
|
||||
self._metadata: Optional["FactorManager"] = None
|
||||
if metadata_path is not None:
|
||||
from src.factors.metadata import FactorManager
|
||||
|
||||
self._metadata = FactorManager(metadata_path)
|
||||
|
||||
def register(
|
||||
self,
|
||||
name: str,
|
||||
@@ -175,6 +185,76 @@ class FactorEngine:
|
||||
# 委托给现有的 register 方法
|
||||
return self.register(name, node, data_specs)
|
||||
|
||||
def add_factor_by_name(
|
||||
self,
|
||||
name: str,
|
||||
factor_name_in_metadata: Optional[str] = None,
|
||||
data_specs: Optional[List[DataSpec]] = None,
|
||||
) -> "FactorEngine":
|
||||
"""根据 metadata 中的因子名称注册因子。
|
||||
|
||||
从 metadata 管理器中根据因子名称查询 DSL 表达式,
|
||||
然后解析并注册到引擎中。
|
||||
|
||||
Args:
|
||||
name: 要注册的因子名称(引擎中使用的名称)
|
||||
factor_name_in_metadata: metadata 中的因子名称,
|
||||
为 None 时默认使用 name 参数
|
||||
data_specs: 可选的数据规格
|
||||
|
||||
Returns:
|
||||
self,支持链式调用
|
||||
|
||||
Raises:
|
||||
RuntimeError: 当引擎未配置 metadata 路径时
|
||||
ValueError: 当在 metadata 中未找到因子时
|
||||
FormulaParseError: 当 DSL 表达式解析失败时
|
||||
|
||||
Example:
|
||||
>>> # 初始化时启用 metadata
|
||||
>>> engine = FactorEngine(metadata_path="data/factors.jsonl")
|
||||
>>>
|
||||
>>> # 注册 metadata 中的因子(使用相同名称)
|
||||
>>> engine.add_factor_by_name("return_5")
|
||||
>>>
|
||||
>>> # 使用不同名称注册
|
||||
>>> engine.add_factor_by_name("my_mom", "momentum_5d")
|
||||
>>>
|
||||
>>> # 链式调用
|
||||
>>> (engine
|
||||
... .add_factor_by_name("ma20")
|
||||
... .add_factor_by_name("rsi14")
|
||||
... .compute(["ma20", "rsi14"], "20240101", "20240131"))
|
||||
"""
|
||||
if self._metadata is None:
|
||||
raise RuntimeError(
|
||||
"引擎未配置 metadata 路径。请在初始化时传入 metadata_path 参数,"
|
||||
+ "例如:FactorEngine(metadata_path='data/factors.jsonl')"
|
||||
)
|
||||
|
||||
# 使用传入的名称或默认使用 name
|
||||
query_name = (
|
||||
factor_name_in_metadata if factor_name_in_metadata is not None else name
|
||||
)
|
||||
|
||||
# 从 metadata 查询因子
|
||||
df = self._metadata.get_factors_by_name(query_name)
|
||||
|
||||
if len(df) == 0:
|
||||
raise ValueError(
|
||||
f"在 metadata 中未找到因子 '{query_name}'。"
|
||||
+ "请确认因子名称正确,或先使用 FactorManager 添加该因子。"
|
||||
)
|
||||
|
||||
# 获取 DSL 表达式
|
||||
dsl_expr = df["dsl"][0]
|
||||
|
||||
# 解析表达式为 Node
|
||||
node = self._parser.parse(dsl_expr)
|
||||
|
||||
# 委托给 register 方法
|
||||
return self.register(name, node, data_specs)
|
||||
|
||||
def compute(
|
||||
self,
|
||||
factor_names: Union[str, List[str]],
|
||||
|
||||
Reference in New Issue
Block a user