因子管理

hikyuu提供了完善的因子管理体系,包括单个因子 Factor 和因子集合 FactorSet 的管理。因子是量化分析的基础构建块,通常由技术指标或其他计算公式构成。

最佳实践

  1. 命名规范: 因子名称应具有描述性且不区分大小写

  2. 因子集组织: 将相关的因子组织到同一个FactorSet中便于管理

  3. 数据验证: 使用 check=True 参数验证股票列表是否属于指定板块

  4. 因子更新: 每日行情数据下载完成后,应及时调用 update_all_factors_values() 更新所有存储的因子值,确保因子数据与行情数据同步。该方法未集成到 HikyuuTdx 和 importdata 中,需要自行手工调用,原因是有时需要进行数据检查,确认数据无误后再进行因子值保存。

  5. 因子值保存: 对于高频聚合的因子值或高频因子值,建议设置 need_save_value=True 并保存到数据库。由于 Hikyuu的超高计算速度,普通的日频因子值(如MA5),通常不建议保存到数据库,因为从存储中读取因子值速度更更慢,这和其他的量化框架依赖因子存储来提升速度的习惯有所不同。建议自行根据需要测试决定。通常直接保存原始因子值,不需要进行截面、标准化等处理,可以由 MF 完成。对需要截面值的因子,通常需要指定对应的证券集,Factor和FactorSet直接指定。

  6. 特殊因子值保存: 对于不通过指标计算的特殊因子值(如PRICELIST或Indicator()),可以使用 save_special_values_to_db() 方法直接保存预计算的因子值

  7. 捐赠用户功能使用: ⚠️ 因子相关的数据库存储和读取操作均为捐赠用户功能,数据库引擎仅支持ClickHouse。使用前请确认已获得相应权限。包括但不限于:save_to_db()remove_from_db()save_values()get_all_values()get_values() 等涉及数据库的操作方法。

注意事项

  • 因子名称和K线类型的组合是唯一的标识符

  • FactorSet 添加同名因子时会覆盖原有的因子

  • 因子集中的因子保持添加顺序

  • 因子计算结果的日期对齐需要参考证券进行同步

  • ⚠️ 所有涉及数据库的操作方法均为捐赠用户功能,仅支持ClickHouse数据库引擎

  • Block变更处理:当Factor或FactorSet的block(证券集合)发生变化时,系统不会自动更新已保存的因子值。如果股票集发生变化,需要自行删除原有因子/因子集后重新创建,或直接创建新的因子/因子集。建议在创建时就明确指定固定的证券集合,避免后续变更。

Factor类

Factor 类用于表示单个因子,包含了因子的基本信息、计算公式和相关属性。

Factor构造函数

# 默认构造函数
Factor()

# 只指定名称和K线类型(用于从数据库加载已有因子)
Factor(name, ktype=KQuery.DAY)

# 创建新的因子对象
Factor(name, formula, ktype=KQuery.DAY, brief="", details="", need_save_value=False, start_date=Datetime.min(), block=Block(), recover_type=KQuery.NO_RECOVER)

参数说明:

  • name (str): 因子名称

  • formula (Indicator): 计算公式指标,一旦创建不可更改

  • ktype (KQuery.KType): K线类型,默认为日线

  • brief (str): 简要描述,默认为空

  • details (str): 详细描述,默认为空

  • need_save_value (bool): 是否需要持久化保存因子值数据,默认为False。设置为True时,将因子指定股票集合从start_date开始的计算值保存到数据库中。由于Hikyuu的计算速度远快于数据库存储,通常日频因子计算的各证券值不建议保存到数据库,需要保存到数据库的通常为高频聚合到日频的因子值或高频因子值

  • start_date (Datetime): 开始日期,数据存储时的起始日期,默认为最小日期

  • block (Block): 板块信息,证券集合,如果为空则为全部,默认为空

  • recover_type (KQuery.RecoverType): 恢复类型,默认为 NO_RECOVER

注意: 因子名称不区分大小写,以 name + ktype 作为唯一标识

Factor属性

属性 类型 描述
name str 因子名称
ktype KQuery.KType 因子频率类型
create_at Datetime 创建日期
update_at Datetime 更改日期
formula Indicator 因子计算公式
start_date Datetime 数据存储起始日期
block Block 证券集合
brief str 基础说明
details str 详细说明
need_save_value bool 是否持久化保存因子值数据

方法

数据库操作 ⚠️ 捐赠用户功能

注意

以下数据库操作方法均为捐赠用户功能,仅支持ClickHouse数据库引擎。

# 保存因子元数据到数据库 ⚠️ 捐赠用户功能
factor.save_to_db()

# 从数据库中删除因子及其数据 ⚠️ 捐赠用户功能
factor.remove_from_db()

# 特殊因子保存值到数据库 ⚠️ 捐赠用户功能
factor.save_special_values_to_db(stock, dates, values, replace=False)

数据获取 ⚠️ 捐赠用户功能

注意

以下数据获取方法,如因子值本身存储在数据库中,则需 捐赠用户 权限,仅支持 ClickHouse 数据库引擎。

# 获取单个证券的计算结果 ⚠️ 捐赠用户功能
result = factor.get_value(stock, query, align=False, fill_null=False, tovalue=False, check=False, align_dates=DatetimeList())

# 获取所有计算结果 ⚠️ 捐赠用户功能
results = factor.get_all_values(query, align=False, fill_null=False, tovalue=False, align_dates=DatetimeList())

# 获取指定证券列表的计算结果 ⚠️ 捐赠用户功能
results = factor.get_values(stocks, query, align=False, fill_null=False, tovalue=False, check=False, align_dates=DatetimeList())

# 保存计算结果到数据库 ⚠️ 捐赠用户功能
factor.save_values(stocks, query, replace=False)

参数说明:

  • stock (Stock): 证券对象(仅 get_value 方法)

  • query (Query): 查询参数

  • align (bool): 是否对齐日期,默认 False

  • fill_null (bool): 是否填充空值,默认 False

  • tovalue (bool): 是否转换为数值,默认 False

  • check (bool): 是否检查股票属于自身指定的 block,默认 False(仅 get_value 和 get_values 方法)

  • align_dates (DatetimeList): 对齐日期列表,默认为空

  • stocks (sequence): 证券列表

  • replace (bool): 是否替换已有数据,默认 False

返回值:

  • get_value: 返回单个 Indicator 对象,表示指定证券的计算结果

  • get_all_values: 返回 Indicator 列表,包含所有证券的计算结果

  • get_values: 返回 Indicator 列表,按股票顺序排列的计算结果

特殊因子值保存方法 ⚠️ 捐赠用户功能

对于某些特殊因子,其值不是通过指标公式计算得出,而是预先准备好的数据,可以使用特殊因子值保存方法。该方法支持两种输入格式:

重载版本1:保存Indicator对象
# 保存Indicator对象的结果数据 ⚠️ 捐赠用户功能
factor.save_special_values_to_db(stock, indicator, replace=False)

参数说明:

  • stock (Stock): 证券对象

  • indicator (Indicator): 已计算好的指标对象(必须已绑定K线数据)

  • replace (bool): 是否替换已有数据,默认False

重载版本2:保存预计算数据
# 保存预计算的日期-值对数据 ⚠️ 捐赠用户功能
factor.save_special_values_to_db(stock, dates, values, replace=False)

参数说明:

  • stock (Stock): 证券对象

  • dates (DatetimeList): 因子值对应的日期列表

  • values (PriceList): 因子值列表

  • replace (bool): 是否替换已有数据,默认False

使用场景:

  • 保存复合指标计算结果

  • 保存外部导入的财务数据

  • 保存机器学习模型预测结果

  • 保存人工标注的特殊因子值

  • 保存从其他数据源获取的因子数据

注意事项:

  • 当使用Indicator对象时,该对象必须已经绑定了具体的K线数据(即有有效的context)

  • 当使用日期-值对时,日期列表和值列表长度必须相等

  • Indicator对象可以通过 .getDateList().getResult(0)方法提取所需数据

Factor使用示例

from hikyuu import *

# 创建因子对象
special_factor = Factor("SPECIAL_FACTOR", PRICELIST(), KQuery.DAY, "特殊因子", "预计算因子值")
special_factor.save_to_db()

stock = sm['sh600000']

# 方式1:保存Indicator对象
k_data = stock.getKData(Query(Datetime(20240101), Datetime(20240110)))
complex_indicator = MA(CLOSE(), 10)(k_data) + RSI(CLOSE(), 14)(k_data) * 0.1
special_factor.save_special_values_to_db(stock, complex_indicator)

# 方式2:保存预计算的日期-值对
dates = DatetimeList([Datetime(20240101), Datetime(20240102), Datetime(20240103)])
values = PriceList([1.2, 1.5, 1.3])
special_factor.save_special_values_to_db(stock, dates, values)

# 从Indicator提取数据保存示例
extracted_dates = complex_indicator.getDateList()
extracted_values = complex_indicator.getResult(0)
special_factor.save_special_values_to_db(stock, extracted_dates, extracted_values)

# 验证保存结果
query_test = Query(Datetime(20240101), Datetime(20240110))
saved_values = special_factor.get_values([stock], query_test)
print(f"保存的因子值: {saved_values[0].getResult(0)}")

FactorSet类

FactorSet 类用于管理一组相关的因子,提供批量操作和集合管理功能。

FactorSet构造函数

# 默认构造函数
FactorSet()

# 创建指定名称和类型的因子集
FactorSet(name, ktype=KQuery.DAY, block=Block())

# 使用指标列表创建因子集合
FactorSet(inds, ktype=KQuery.DAY)

参数说明:

  • name (str): 因子集名称

  • ktype (KQuery.KType): K线类型,默认为日线

  • block (Block): 板块信息,证券集合,默认为空

  • inds (list): 指标列表

注意: 使用指标列表创建时,同名的指标会被覆盖,最终保留最后一个同名指标

FactorSet属性

属性 类型 描述
name str 因子集名称
ktype KQuery.KType 因子集频率类型
block Block 因子集对应的板块

基本方法

# 检查是否为空
is_empty = factor_set.empty()

# 清空因子集
factor_set.clear()

# 检查是否为null值
is_null = factor_set.is_null()

# 获取因子数量
count = len(factor_set)

因子管理方法

# 添加因子
factor_set.add(factor)           # 添加单个Factor对象
factor_set.add(indicator)        # 添加Indicator对象
factor_set.add(indicator_list)   # 添加Indicator列表
factor_set.add(factor_list)      # 添加Factor列表

# 检查是否存在指定因子
exists = factor_set.has_factor("MA5")

# 获取指定因子
factor = factor_set.get_factor("MA5")

# 移除因子
factor_set.remove_factor("MA5")

# 获取所有因子
factors = factor_set.get_factors()

数据获取方法

# 获取所有因子的计算结果
all_results = factor_set.get_all_values(query, align=False, fill_null=False, tovalue=False, align_dates=DatetimeList())

# 获取指定证券列表的计算结果
results = factor_set.get_values(stocks, query, align=False, fill_null=False, tovalue=False, check=False, align_dates=DatetimeList())

参数说明:

  • query (Query): 查询参数

  • align (bool): 是否对齐日期,默认False

  • fill_null (bool): 是否填充空值,默认False

  • tovalue (bool): 是否转换为数值,默认False

  • check (bool): 是否检查股票列表属于自身指定的block,默认False

  • align_dates (DatetimeList): 对齐日期列表,默认为空

  • stocks (sequence): 证券列表

迭代器支持

# 遍历所有因子
for factor in factor_set:
    print(f"因子名称: {factor.name}")

# 通过索引访问
first_factor = factor_set[0]
named_factor = factor_set["MA5"]

FactorSet使用示例

from hikyuu import *

# 创建多个技术指标因子
ma5 = MA(CLOSE(), 5)
ma10 = MA(CLOSE(), 10)
rsi = RSI(CLOSE(), 14)

# 设置因子名称
ma5.name = "MA5"
ma10.name = "MA10" 
rsi.name = "RSI"

# 创建因子集
factor_set = FactorSet("技术指标因子集", KQuery.DAY)

# 添加因子
factor_set.add(ma5)
factor_set.add(ma10)
factor_set.add(rsi)

# 或者直接从指标列表创建
indicators = [ma5, ma10, rsi]
factor_set2 = FactorSet(indicators, KQuery.DAY)

print(f"因子集包含 {len(factor_set)} 个因子")

# 遍历因子
for factor in factor_set:
    print(f"- {factor.name}: {factor.brief}")

# 获取计算结果
stocks = blocka.get_stock_list()[:10]  # 获取前10只A股
query = Query(Datetime(20240101), Datetime(20241231))
results = factor_set.get_values(stocks, query)

# 检查特定因子
if factor_set.has_factor("MA5"):
    ma5_factor = factor_set.get_factor("MA5")
    print(f"找到MA5因子: {ma5_factor.details}")

与多因子合成的结合使用

因子和因子集可以与多因子合成算法配合使用:

from hikyuu import *

# 方法1: 使用Indicator列表
indicators = [MA(CLOSE(), 5), MA(CLOSE(), 10)]
weights = [0.6, 0.4]
mf1 = MF_Weight(indicators, stocks, weights, query)

# 方法2: 使用FactorSet
factor_set = FactorSet(indicators)
mf2 = MF_Weight(factor_set, stocks, weights, query)

# 等权重合成
mf_equal = MF_EqualWeight(factor_set, stocks, query)

全局因子管理函数 ⚠️ 捐赠用户功能

⚠️ 重要提醒

以下所有全局因子管理函数均为捐赠用户功能,数据库引擎仅支持ClickHouse。

除了Factor和FactorSet类的方法外,hikyuu还提供了一系列全局函数用于因子的数据库管理和批量操作。

因子数据库操作 ⚠️ 捐赠用户功能

get_factor(name[, ktype=KQuery.DAY]) ⚠️ 捐赠用户功能

获取指定名称和类型的因子元数据

from hikyuu import *

# 获取日线因子 ⚠️ 捐赠用户功能
factor = get_factor("MA5")
# 获取周线因子 ⚠️ 捐赠用户功能
weekly_factor = get_factor("MA5", KQuery.WEEK)

参数说明:

  • name (str): 因子名称

  • ktype (KQuery.KType): K线类型,默认为日线

返回值: 因子对象,如果不存在则返回空因子

save_factor(factor[, update_before=True]) ⚠️ 捐赠用户功能

保存因子到数据库

# 创建并保存因子(默认会检查并更新已有因子)⚠️ 捐赠用户功能
ma5 = MA(CLOSE(), 5)
ma5.name = "MA5"
ma5_factor = Factor("MA5", ma5)
save_factor(ma5_factor)

参数说明:

  • factor (Factor): 要保存的因子对象

  • update_before (bool): 是否在保存前检查并更新已有因子,默认为True。注意:通常必须为true,否则会导致数据错误,除非确定所有因子值都已更新

注意:name + ktype 作为唯一标识

remove_factor(name, ktype) ⚠️ 捐赠用户功能

从数据库中删除因子

# 删除指定因子 ⚠️ 捐赠用户功能
remove_factor("MA5", KQuery.DAY)

参数说明:

  • name (str): 因子名称

  • ktype (KQuery.KType): K线类型

注意:name + ktype 作为唯一标识

get_all_factors() ⚠️ 捐赠用户功能

获取所有因子元数据

# 获取所有因子 ⚠️ 捐赠用户功能
all_factors = get_all_factors()
print(f"共有 {len(all_factors)} 个因子")

# 遍历所有因子
for factor in all_factors:
    print(f"- {factor.name} ({factor.ktype})")

返回值: 所有因子对象列表

update_all_factors_values([ktype=KQuery.DAY]) ⚠️ 捐赠用户功能

更新所有因子值(增量更新)

# 更新所有日线因子值 ⚠️ 捐赠用户功能
update_all_factors_values()

# 更新所有周线因子值 ⚠️ 捐赠用户功能
update_all_factors_values(KQuery.WEEK)

参数说明:

  • ktype (KQuery.KType): K线类型,默认为日线

使用场景: 每日行情数据下载完成后,可以调用此函数更新所有存储的因子值。该操作为增量更新,只计算新增数据部分,提高更新效率。

因子集数据库操作 ⚠️ 捐赠用户功能

save_factorset(set) ⚠️ 捐赠用户功能

保存因子集到数据库

# 创建并保存因子集 ⚠️ 捐赠用户功能
indicators = [MA(CLOSE(), 5), MA(CLOSE(), 10)]
factor_set = FactorSet(indicators)
factor_set.name = "均线因子集"
save_factorset(factor_set)

参数说明:

  • set (FactorSet): 要保存的因子集对象

注意:name + ktype 作为唯一标识

get_factorset(name[, ktype=KQuery.DAY]) ⚠️ 捐赠用户功能

获取因子集

# 获取因子集 ⚠️ 捐赠用户功能
factor_set = get_factorset("均线因子集")
# 获取周线因子集 ⚠️ 捐赠用户功能
weekly_set = get_factorset("均线因子集", KQuery.WEEK)

参数说明:

  • name (str): 因子集名称

  • ktype (KQuery.KType): K线类型,默认为日线

返回值: 因子集对象,如果不存在则返回空因子集

remove_factorset(name, ktype) ⚠️ 捐赠用户功能

从数据库中删除因子集

# 删除指定因子集 ⚠️ 捐赠用户功能
remove_factorset("均线因子集", KQuery.DAY)

参数说明:

  • name (str): 因子集名称

  • ktype (KQuery.KType): K线类型

注意:name + ktype 作为唯一标识

get_all_factorsets() ⚠️ 捐赠用户功能

获取所有因子集

# 获取所有因子集 ⚠️ 捐赠用户功能
all_sets = get_all_factorsets()
print(f"共有 {len(all_sets)} 个因子集")

# 遍历所有因子集
for factor_set in all_sets:
    print(f"- {factor_set.name} ({factor_set.ktype}): {len(factor_set)}个因子")

返回值: 所有因子集对象列表

全局因子管理使用示例

from hikyuu import *

# 1. 创建并管理因子
ma5 = MA(CLOSE(), 5)
ma5.name = "MA5"
ma5_factor = Factor("MA5", ma5, brief="5日均线")

rsi = RSI(CLOSE(), 14)
rsi.name = "RSI"
rsi_factor = Factor("RSI", rsi, brief="14日相对强弱指数")

# 保存到数据库
# 也可以不保存,保存到数据库的优势:后续可以直接: ma5 = Factor('MA5) , 会自动从数据库加载获取因子定义
# 默认创建的因子 need_save_value=False,如需同时保存因子值,需将 need_save_value=True,保存时将自动计算所有因子值并存储
save_factor(ma5_factor)
save_factor(rsi_factor)

# 2. 创建因子集
tech_indicators = [ma5, rsi]
factor_set = FactorSet(tech_indicators)
factor_set.name = "技术指标集"
save_factorset(factor_set)

# 3. 查询和使用
# 获取所有因子
all_factors = get_all_factors()
print(f"数据库中共有 {len(all_factors)} 个因子")

# 获取特定因子集
loaded_set = get_factorset("技术指标集")
if not loaded_set.is_null():
    print(f"加载因子集: {loaded_set.name}, 包含 {len(loaded_set)} 个因子")
  
    # 使用因子集进行计算
    stocks = blocka.get_stock_list()[:5]
    query = Query(Datetime(20240101), Datetime(20241231))
    results = loaded_set.get_values(stocks, query)
    print("计算完成")

# 4. 清理不需要的因子
# remove_factor("MA5", KQuery.DAY)
# remove_factorset("技术指标集", KQuery.DAY)

常见问题 FAQ

Q: 因子值的精度是如何保证的?

A: 系统使用float64存储,支持双精度浮点数,能够精确表示大部分金融计算所需的数值范围。

Q: 对于高频因子值有什么特殊考虑吗?

A: 高频因子值的处理建议:

  • 考虑是否真的需要保存到数据库(Hikyuu计算速度很快)

  • 根据实际需求测试决定存储策略

Q: 当我修改了因子的证券集合(block)后,之前保存的因子值如何更新?

A: 当Factor或FactorSet的block(证券集合)发生变化时,系统不会自动更新已保存的因子值。如果您修改了股票集合,您有两种处理方式:

  1. 删除重建:删除原有因子/因子集,然后重新创建并保存

    # 删除旧的因子
    remove_factor("MY_FACTOR", KQuery.DAY)
    
    # 创建并保存新的因子
    new_factor = Factor("MY_FACTOR", formula, block=new_block)
    save_factor(new_factor)
    
  2. 新建因子:使用不同的名称创建新因子/因子集

    # 创建带版本标识的新因子
    updated_factor = Factor("MY_FACTOR_V2", formula, block=new_block)
    save_factor(updated_factor)
    

我们建议在创建因子时就明确指定固定的证券集合,尽量避免后续变更,这样可以减少不必要的维护工作。