Ricequant Docs
  • RQSDK快速上手
  • RQData - 金融数据 API

    • Python API文档
    • Http API文档
  • RQAlpha Plus - 回测框架

    • 使用教程
    • API使用手册 (opens new window)
  • RQFactor - 因子投研工具

    • 使用教程
    • API使用手册
  • RQOptimizer - 股票组合优化器

    • 使用教程
    • API使用手册 (opens new window)
  • RQPAttr - 绩效归因工具

    • 使用教程
  • RQAMS 用户说明文档
  • RQAMSC 说明文档
量化平台文档
米筐帮助中心
返回官网
  • RQSDK快速上手
  • RQData - 金融数据 API

    • Python API文档
    • Http API文档
  • RQAlpha Plus - 回测框架

    • 使用教程
    • API使用手册 (opens new window)
  • RQFactor - 因子投研工具

    • 使用教程
    • API使用手册
  • RQOptimizer - 股票组合优化器

    • 使用教程
    • API使用手册 (opens new window)
  • RQPAttr - 绩效归因工具

    • 使用教程
  • RQAMS 用户说明文档
  • RQAMSC 说明文档
量化平台文档
米筐帮助中心
返回官网
  • RQFactor文档

    • 因子开发指南
    • API文档
      • 内置因子
      • 内置算子
        • 数学符号
        • 简单算子
        • 均线算子
        • 横截面算子
        • FIX
        • 其他算子
      • 自定义算子
        • 抽象类定义
        • 辅助函数
      • 因子计算
        • execute_factor
        • 范例
      • 因子检验 V1.1 (退役中)
        • factor_analysis
        • 范例
      • 因子检验 V1.2
        • FactorAnalysisEngine
        • 1. 预处理可选项
        • 2. 因子分析器可选项
        • 3. 构建管道
        • 4. 执行计算
        • 使用示例
        • 量价因子 范例 1
        • 量价因子 范例 2
        • 月度因子(自然月)范例
        • F-Score 因子范例

在下文中,X、A、B、C表示因子或因子表达式,c 表示常数,n 表示正整数。

zscore:标准分数,通过一个数与平均数的差再除以标准差得到。

对所有因子:编写前,用户需导入米筐因子的相关信息:

from rqfactor import *

# 内置因子

用户在编写新的因子时,可在表达式中引用一些常见的行情因子、财务因子和技术因子。可引用的因子分为三部分: 行情因子, 财务因子 以及技术因子。

  • 行情因子

    • 行情因子的引用方式: Factor('factor')

    • 其中 因子 包含以下七个因子:

因子 类型 说明
open float 开盘价
close float 收盘价
high float 最高价
low float 最低价
total_turnover float 总成交额
volume float 总成交量
num_trades float 成交笔数
  • 财务因子

    • 财务因子的引用方式: Factor('factor')
    • 其中可引用的财务因子 见: 基础财务数据、衍生财务指标.
  • alpha101 因子

    • alpha101 因子的调用方式: Factor('factor'),具体因子详情可见alpha101 因子
  • 技术因子

    • 技术因子的调用方式: Factor('factor'),具体因子详情可见技术指标
  • 举例

    • 自定义因子中引用行情相关的因子

      from rqfactor import *
      def compute():
          return Factor('open') + Factor('close')
      
    • 自定义因子中引用财务类的因子。

      from rqfactor import *
      def compute():
          return Factor('pe_ratio')
      
    • 自定义因子中引用技术类因子。

      from rqfactor import *
      def compute():
          return KDJ_K
      
    • 自定义财务因子。

      from rqfactor import *
      def compute():
          return 1/Factor('pe_ratio') + 1/Factor('pb_ratio') + Factor('return_on_equity')
      

# 内置算子

# 数学符号

支持下列数学符号:

符号 含义
+ 加法,两个因子或一个因子与一个常数相加
- 减法,两个因子或一个因子与一个常数相减
* 乘法,两个因子或一个因子与一个常数相乘
/ 除法,两个因子或一个因子与一个常数相除
** 幂,参考 np.power,可以为两个因子或一个因子及一个常数
// 整除,两个因子或一个因子与一个常数整除
% 取模,两个因子或一个因子与一个常数取模
> 大于,两个因子或一个因子与一个常数比较
< 小于
>= 大于等于
<= 小于等于
& 与,两个因子或一个因子与一个常数做逻辑与
| 或,两个因子或一个因子与一个常数做逻辑或
~ 非,对因子取反
!= 不等于,两个因子或一个因子与一个常数比较

# 简单算子

算子 含义
ABS(X) 取因子的绝对值
LOG(X) 取因子的对数值
EXP(X) e 的 x 次幂,x 指因子值。参考 np.exp
LOG(X) 取因子的自然对数
EQUAL(A, B) 比较两个因子或一个因子与一个常数
SIGN(X) 取因子值的符号,参考 np.sign
SIGNEDPOWER(X, c) 计算因子值的 c 次方,保持符号不变;c 为常数
MIN(A, B) 对A、B 两个因子,取其中较小的值
FMIN(A, B) 与 MIN 类似,但当其中一个值为 NaN 时,FMIN返回另一个值,MIN 则相反
MAX(A, B) 对A、B 两个因子,取其中较大的值
FMAX(A, B) 与 MAX 类似,但当其中一个值为 NaN 时,FMAX 返回另一个值,MAX 则相反
IF(C, A, B) 当因子 C 值为 True 时,返回因子 A 的值;反之则返回因子 B 的值
AS_FLOAT(X) 将因子 X 的值转换为浮点类型
REF(X, n) 返回 n 个交易日前 X 的值
DELAY(X, n) REF 的别名
DELTA(X, n) X - REF(X, n)
PCT_CHANGE(X, n) X / REF(X, n) - 1.0

# 均线算子

# DMA

  • DMA(X, c)
    对于序列 x 及常数 c,DMA 变换的结果为:
    y[0] = x[0]
    y[i] = y[i-1] * (1 - c) + x[i] * c
  • DMA(A, B)
    对于序列a、b,DMA 变换的结果为:
    y[0] = a[0]
    y[i] = y[i-1] * (1 - b[i]) + a[i] * b[i]

# MA 及 SMA

  • SMA_CN(X, n, m) 国内常用行情软件中的 SMA 算子,相当于 DMA(X, m / n)
  • SMA(X, n) MA 的别名
  • MA(X, n) 简单移动平均,与 talib 中 MA 相同

# EMA

  • EMA_CN(X, n) 指数平滑移动平均,相当于 DMA(X, 2 / (N + 1))
  • EMA(X, n) 指数平滑移动平均,返回收盘价 n 个交易日的指数平滑移动平均

# WMA

  • WMA(X, n) 与 talib 中 WMA 相同
  • DECAY_LINEAR(X, n) WMA 的别名

# 横截面算子

# RANK

RANK(X, method='average', ascending=True)
对股票池中股票的因子值排序,返回值为经过归一化后的排名,即名次 / 参与排名的数据个数。对于 NaN 值,返回 NaN。

  • method: 可选 average, min, max, first, dense,其意义与 pandas.DataFrame.rank 中 method 字段相同;
  • ascending: 排序方向,默认为从小到大
  • 例如:RANK(Factor('close'), 'first', True) 返回今天收盘价在过去股票池内的升序排序占比,若多项值相同,则按它们出现在数组中的顺序进行排序;

# SCALE

SCALE(X, to=1) 对股票池中的因子值进行缩放,使其绝对值的和等于 to

  • 例如:SCALE(Factor('close'), 10) 给定股票池,将股票池内收盘价量级调整进行调整,使绝对值之和等于 10

# DEMEAN

DEMEAN(X) 对股票池中的因子值减去其均值,从而使得和为 0

  • 例如:DEMEAN(Factor('close')) 给定股票池,返回每只股票的收盘价减去收盘价的均值

# CS_ZSCORE

CS_ZSCORE(X) 求股票池中因子值的 zscore

  • 例如:CS_ZSCORE(Factor('close')) 给定股票池,返回收盘价在选定股票池的标准化值

# QUANTILE

QUANTILE(X, bins=5, ascending=True) 将因子值按大小划分为 bins 组,返回对应的组序号。参考 pandas.qcut

  • 例如:QUANTILE(Factor('close'), bins = 5, ascending = True) 表示对收盘价按升序分为 5 组

# TOP

TOP(X, threshold=50, pct=False)

  • 当 pct 为 False 时,因子值处于 top threshold 的股票返回 1,其他返回 0;
  • 当 pct 为 True 时,因子值处于前 threshold 百分位的股票返回 1,其他返回 0。
  • 例如:TOP(Factor('close'), threshold=50, pct=False) 在股票池中排名前 50 的返回 1,其余为 0

# BOTTOM

BOTTOM(X, threshold=50, method="ordinal") 与 TOP 类似,取排名较后的

  • 例如:BOTTOM(Factor('close'), threshold=50, method='ordinal') 在股票池中排名最后 50 的返回 1,其余为 0

# INDUSTRY_NEUTRALIZE

INDUSTRY_NEUTRALIZE(X) 对因子 X 进行行业中性化

  • 例如:INDUSTRY_NEUTRALIZE(Factor('close')) 选定股票池,根据申万行业分类对收盘价进行行业中性化处理

# CS_REGRESSION_RESIDUAL

CS_REGRESSION_RESIDUAL(Y, *X, add_const=True) 使用一个或多个因子 *X 作为自变量,Y 作为因变量进行回归,返回残差

  • 例如:CS_REGRESSION_RESIDUAL (Factor('close'), Factor('open'), Factor('high'))

# CS_FILLNA

CS_FILLNA(X) 用行业均值填充缺失值

# FIX

FIX(X, order_book_id)
固定返回因子 X 在标的 order_book_id 的值,如 FIX(Factor('close'), '000300.XSHG') 将总是返回 000300.XSHG 的收盘价。
常用于计算股票与指数关系,如 CORR(PCT_CHANGE(Facotr('close')), FIX(PCT_CHANGE(Factor('close')), '000300.XSHG'))
可计算股票收益率与沪深 300 收益率的相关性。

# 其他算子

# AVEDEV

AVEDEV(X, n) X 最近 n 期因子值相对于其平均值的绝对偏差的平均值

# STD

STD(X, n) X 最近 n 期因子值的标准差,与 talib 中 STDDEV 相同

  • 例如:STD(Factor('close'), 10) 表示收盘价 10 个交易日的标准差

# STDDEV

STDDEV(X, n) STD 的别名

# VAR

VAR(X, n) X 最近 n 期因子值的方差,与 talib 中 VAR 相同

  • 例如:VAR(Factor('close'), 10) 表示收盘价在过去 10 个交易日内的方差

# CROSS

CROSS(A, B) (A[i-1] <= B[i-1]) and A[i] > B[i],即 A 从下方穿越 B

  • 例如:CROSS( MA(Factor('close'), 5), MA(Factor('close'), 10)) 返回 5 日均线与 10 日均线金叉

# TS_SKEW

TS_SKEW(X, n) 最近 n 期因子值的偏度

  • 例如:TS_SKEW(Factor('close'), 60) 返回收盘价过去 60 个交易日的偏度

# TS_KURT

TS_KURT(X, n) 最近 n 期因子值的峰度

  • 例如:TS_KURT(Factor('close'), 60) 返回收盘价过去 60 个交易日的峰度

# SLOPE

SLOPE(X, n) 最近 n 期因子值的斜率,与 talib 中 LINEARREG_SLOPE 相同

# SUM

SUM(X, n) 最近 n 期因子值的和

  • 例如:SUM(Factor('volume'), 10) 统计 10 个交易日成交量的总和

# PRODUCT

PRODUCT(X, n) 最近 n 期因子值的乘积

  • 例如:PRODUCT(Factor('close'), 10) 表示过去 10 个交易日收盘价的移动平均求积

# TS_MIN

TS_MIN(X, n) 最近 n 期因子值的最小值,与 talib 中 MIN 相同

  • 例如:TS_MIN(Factor('close'), 5) 返回过去 5 个交易日中收盘价的最小值

# TS_MAX

TS_MAX(X, n) 最近 n 期因子值的最大值,与 talib 中 MAX 相同

  • 例如:TS_MAX(Factor('close'), 5) 返回过去 5 个交易日中收盘价的最大值

# LLV

LLV(X, n) TS_MIN 的别名

  • 例如:LLV(Factor('close'), 10) 表示 10 个交易日内收盘价的最小值

# HHV

HHV(X, n) TS_MAX 的别名

  • 例如:HHV(Factor('close'), 10) 表示 10 个交易日内收盘价的最大值

# TS_ARGMIN

TS_ARGMIN(X, n) 最近 n 期因子值中最小值的序号,与 talib 中 MININDEX 相同

  • 例如:TS_ARGMIN(Factor('close'), 5) 返回过去 5 个交易日中收盘价的最小值的索引

# TS_ARGMAX

TS_ARGMAX(X, n) 最近 n 期因子值中最大值的序号,与 talib 中 MAXINDEX 相同

  • 例如:TS_ARGMAX(Factor('close'), 5) 返回过去 5 个交易日中收盘价的最大值的索引

# CORR

CORR(A, B, n) 因子 A 及 B 最近 n 期因子值的相关性,与 talib 中 CORREL 相同

  • 例如:CORR(Factor('close'), Factor('open'), 66) 表示过去 66 个交易日收盘价与开盘价的相关系数

# CORRELATION

CORRELATION(A, B, n) CORR 的别名

# COVARIANCE

COVARIANCE(A, B, n) 因子 A 及 B 最近 n 期因子值的协方差

# COV

COV(A, B, n) COVARIANCE 的别名

  • 例如:COV(Factor('open'), Factor('close'), 66) 表示过去 66 个交易日收盘价与开盘价的协方差

# COUNT

COUNT(X, n) 最近 n 期因子值中为 True 的数量

  • 例如:COUNT(Factor('close'), 10) 表示过去 10 个交易日收盘价的移动平均求积 lF

# EVERY

EVERY(X, n) EQUAL(COUNT(X, n), n)

  • 例如:EVERY(Factor('close') > Factor('open'), 10) 表示若 10 个交易日内一直是阳线,则返回 True,否则返回 False

# TS_RANK

TS_RANK(X, n) 最新值在最近 n 期中的排名百分位

  • 例如:如 N=5,今天的 X 排序为 3,则返回 0.6

# TS_ZSCORE

TS_ZSCORE(X, n) 最新值在最近 n 期中的 zscore

  • 例如:TS_ZSCORE (Factor('close'), 10) 表示收盘价在过去 10 个交易日的取值作为样本,返回当前交易日收盘价对应的标准分数

# TS_REGRESSION

TS_REGRESSION(Y, X, n) 对最新 n 期因子值,使用 Y作为因变量,X作为自变量进行回归,回归系数作为结果

  • 例如:TS_REGRESSION(Factor('close'),Factor('open'),60) 返回收盘价为因变量,开盘价为自变量在过去 60 个交易日的回归参数

# TS_FILLNA

TS_FILLNA(X, nv, method='value') 缺失值填充
根据 method 的值,使用不同的方式对缺失值进行填充:

  • value: 将 NaN 替换为 nv
  • MA: 使用前 nv 期因子均值填充
  • forward: 向前搜索直到找到非 NaN 的值,但不超过 nv 项,用找到的值填充

# 自定义算子

以下函数及类均定义在 rqfactor.extension 包中。

# 抽象类定义

# CombinedFactor

CombinedFactor(func, *factors) 简单复合因子,接受一个函数及一个或多个因子;其接受的函数 func 原型为 def func(*series),series 对应 *factors。

# RollingWindowFactor

RollingWindowFactor(func, window, factor) 滑动窗口因子

  • func: 其原型为 def func(series, window),其中 series 为 factor 的因子值,一维 np.ndarray;window 为滑动窗口大小;
  • window: 滑动窗口大小

# CombinedRollingWindowFactor

CombinedRollingWindowFactor(func, window, *factors) 复合滑动窗口因子

  • func: 其原型为 def func(window, *series), 注意,window 参数在前;
  • window: 滑动窗口大小

# CombinedCrossSectionalFactor

CombinedCrossSectionalFactor(func, *factors): 复合横截面因子,接受一个函数及一个或多个因子;func函数的原型为 def func(df1, df2, ...), 每个因子对应一个 DataFrame;

# UserDefinedLeafFactor

UserDefinedLeafFactor(name, func) 用于创建自定义基础因子

  • name: 自定义因子的名字;
  • func: 其原型如下:
    def func(order_book_ids, start_date, end_date):
        """
        @param order_book_ids: 股票/指数代码列表,如 ['000001.XSHE', '600000.XSHG']
        @param start_date: 开始日期,pd.Timestamp 类型
        @param end_date: 结束日期,pd.Timestamp 类型
        @return pd.DataFrame, index 为 pd.DatatimeIndex 类型,可通过 pd.to_datetime(rqdatac.get_trading_dates(start_date, end_date)) 生成;column 为 order_book_id;注意,仅包含交易日
        """

# 辅助函数

# rolling_window

rolling_window(series, window):
可参考 这里 (opens new window)。
其功能如下:

In[]:
a = np.arange(100)
rolling_window(a, 20)
Out[]:
array([[ 0,  1,  2, ..., 17, 18, 19],
    [ 1,  2,  3, ..., 18, 19, 20],
    [ 2,  3,  4, ..., 19, 20, 21],
    ...,
    [78, 79, 80, ..., 95, 96, 97],
    [79, 80, 81, ..., 96, 97, 98],
    [80, 81, 82, ..., 97, 98, 99]])

# 因子计算

# execute_factor

execute_factor(factor, order_book_ids, start_date, end_date, universe=None): 返回 pd.DataFrame

  • factor: 需要计算的因子
  • order_book_ids: 需要计算的股票列表
  • start_date, end_date: 指定计算的时间范围,支持字符串, datetime.date, datetime.datetime, pd.Timestamp
  • universe: 可以通过此参数指定参与计算的股票池;支持指数代码及 None,None 表示全市场。默认为 None。

您可能需要:在初始化阶段缓存一些必要数据,大量计算因子的时候可以从缓存读取数据,而不需要每次重新从 rqdatac 调取数据.
缓存数据包括: 日行情因子 (默认后复权) ,财务因子,ALpha101 因子,技术指标.
如无指定,则仅会加载后复权的日行情因子 (open,close,high,low,total_turnover,volume,num_trades).
初始化:

CachedExecContext.init(order_book_ids, start_date, end_date, leaves=None, universes=None)

参数如下:

  • start_date, end_date: 限定数据范围,start_date 应不晚于因子值的开始计算日期+因子的最长回望周期
  • leaves: 用于指定初始化的叶子因子列表,如果不指定则默认包含所有日级别行情因子
  • universes: 指定需要缓存的 universe 列表,避免每次计算重新调取

# 范例

from rqfactor.engine_v2 import execute_factor
from rqfactor.engine_v2 import CachedExecContext
from rqfactor import *
from rqdatac import *
init()
start_date, end_date = 20231201,20240101
order_book_ids = ['000001.XSHE','000002.XSHE']
leaves = ['pe_ratio',]
#初始化
CachedExecContext.init(order_book_ids, start_date, end_date,  leaves=leaves)
#计算时指定使用 CachedExecContext
execute_factor(Factor('pe_ratio'), order_book_ids, start_date, end_date, exec_context_class=CachedExecContext)

# 因子检验 V1.1 (退役中)

# factor_analysis

factor_analysis(
    f, period, start_date=None, end_date=None, universe=None, shift=1,
    rank_ic=True, quantile=5, ascending=True, winzorization='mad',
    normalization=True, neutralization='none',
    include_st=True, include_new=True, benchmark='000300.XSHG'
)

参数如下:

  • f: 因子值或因子定义,如 Factor('close')。当传入因子值时,类型为pd.DataFrame,index 为交易日,columns 为 order_book_id。当传入因子定义时,需要同时指定 start_date 及 end_date,可通过 universe 参数设置需要计算的股票范围。
  • period: 调仓周期,5 表示每 5 个交易日进行一次调仓;
  • start_date, end_date: 计算因子值时的时间范围,支持字符串,datetime.date, datetime.datetime, pd.Timestamp。当传入因子值时,这两个参数无效;
  • universe: 计算因子值时股票的范围;默认为全市场。可传入指数代码,如 000300.XSHG,表示计算沪深 300 指数成分的因子值;
  • shift: 因子值延后的期数。一般来说,T日的因子值只能在收盘后获得,用于指导T+1日的调仓,此时设置 shift 为 1 即可。默认为 1;
  • rank_ic: 是否使用因子值的排名计算 ic。为 False 时,使用因子值计算 ic;
  • quantile: 分组数目,默认为 5;
  • ascending: 因子值排序方向,默认为True,表示从小到大排序;False则反向排序;
  • winzorization: 离群值处理方式,可选择 mad(绝对值差中位数法), std(标准差法), percentile(百分位法) 及 none(不进行离群值处理);
  • normalization: 是否对因子值进行标准化;
  • neutralization: 因子中性化方法,可选择 none(不进行中性化处理)、industry(进行行业中性化)、style(进行风格因子中性化)、market(进行市值中性化)
  • include_st: 是否包含 ST 股;
  • include_new: 是否包含新股(上市 180 天以内的股票);
  • benchmark: 基准,默认为 000300.XSHG(沪深 300 指数)

返回 FactorAnalysisResult 类型的对象,包含如下字段:

  • ic: pd.Series类型,各期 ic 值;
  • ic_rolling: pd.Series类型,最多 20 期 ic 衰减均值;
  • ic_summary: dict类型,ic 统计指标,包含一下字段:
    • mean: ic 序列的均值
    • std: ic 序列的标准差
    • positive: ic 为正的个数
    • negative: ic 为负的个数
    • significanse: ic 显著性水平(p 值小于 0.01 的占比)
    • sig_positive: 正 ic 显著性水平
    • sig_negative: 负 ic 显著性水平
    • t_value: 多期 IC 值分布作 T 检验所得到的 T 统计量
    • p_value: 多期 IC 值分布作 T 检验所得到的 P 值
    • skew: ic 序列的偏度
    • kurtosis: ic 序列的峰度
    • ir: IC 序列的均值与标准差的比值
  • quantile_factor_returns: pd.DataFrame 类型,因子分组累积收益率
  • quantile_turnover: pd.DataFrame 类型,各期分组换手率
  • ic_industry_distribute: pd.Series 类型, ic 行业分布
  • benchmark_return: pd.Series 类型,基准累积收益率

还包含 show 方法,可在 Jupyter Notebook 绘制分析结果。

# 范例

  • 基于沪深 300 股票池,对收盘价因子在 20170101-20170601 进行调仓周期为 5 的检验分析
from rqfactor import *
from rqfactor.notebook import *
import rqdatac
rqdatac.init()
f = Factor('close')
df = execute_factor(f, rqdatac.index_components('000300.XSHG', '20170101'), '20170101', '20170601')
result = factor_analysis(df, 5)
result.ic
  • 可以通过show 方法在 Jupyter Notebook对上例的检验结果进行图形化展示,并可以通过save_figs 方法保存图形化结果至本地
from rqfactor import *
from rqfactor.notebook import *
import rqdatac
rqdatac.init()
f = Factor('close')
df = execute_factor(f, rqdatac.index_components('000300.XSHG', '20170101'), '20170101', '20170601')
result = factor_analysis(df, 5)
# 显示图片
result.show(mode='column')  # 默认选项,将所有图片显示成为一列
result.show(mode='split')   # 将所有图片独立显示成为一个html页面,注意,在windows系统中可能会有显示问题。
result.show(mode='grid', ncols=2)   # 将图片按照栅格排列展示在一个页面中,支持额外参数 ncols
# 保存图片API save_figs 支持参数:
# mode: 图像显示的方式,同result.show
# to: 图片保存的路径,支持绝对路径和相对路径,如传入 result.html 则将图像保存到代码运行路径的result.html文件里面,需要注意的是,当选择mode='split'时,会保存五张图片,result.html作为每张图片的后缀
# silent: 图片保存后是否通过浏览器打开,默认是True(不打开)
# filetype: 图片保存的类型,默认html。(现在仅支持html)
# ncols:只有在mode='grid'时生效
result.save_figs(mode='column', to='result.html',silent=True)
result.save_figs(mode='grid', to='./grid_figs.html', ncols=2)

温馨提示:用户需要自行安装 bokeh 包

# 因子检验 V1.2

# FactorAnalysisEngine

# 特点:

  • 不限因子的资产类型和数据频率,因子检验的使用范围更广;
  • 支持传入自定义收益率,不再局限于股票日终收益率;
  • 支持传入自定义资产行业,更灵活地计算 IC 行业分布;
  • 对于多日调仓的场景,使用滚动调仓计算 IC 和因子收益,从而减少路径依赖;
  • 通过构造管道进行数据处理和分析计算,方便用户反复地进行检验和分析;
  • 可单独计算 IC 分析/分组分析/因子收益率,自定义输出结果更有针对性;
  • 支持输出数据处理后的因子值,处理结果更加透明。

注:目前仅支持传入因子值,不支持传入因子定义,如Factor('close')需使用execute_factor计算后再传入。

# 1. 预处理可选项

# 极值处理

Winzorization(method='mad')
# 参数

可选择 mad:3 绝对值差中位数法, std:3 标准差法, percentile:2.5%百分位法

# 标准化

Normalization()

# 因子中性化

Neutralization(industry='citics_2019', style_factors='all')
# 参数
  • industry:行业中性化使用的行业分类,目前仅支持股票。可选citics_2019或者sws,None代表不做行业中性
  • style_factors:需要进行中性化的风格,底层数据为米筐风险因子,目前仅支持股票。None代表不做风格中性;all代表所有风格;支持通过 list 传入单个或者多个风格,可选size市值,beta贝塔,momentum动量,earnings_yield盈利率,growth成长性,liquidity流动性,leverage杠杆率,book_to_price账面市值比,residual_volatility残余波动率,non_linear_size非线性市值

# 2. 因子分析器可选项

# IC 分析

ICAnalysis(rank_ic=True,industry_classification=None, max_decay=None)
# 参数
  • rank_ic: 是否使用因子值的排名计算 ic。为 False 时,使用因子值计算 ic
  • industry_classification: 分组依据,None代表不计算 IC 行业分布;可输入sws或citics_2019,仅支持股票因子;对于股票之外的资产类型,可传入自定义分组pd.Series or dict,其中index或key为资产 id
  • max_decay:计算ic_decay时使用的最大滞后期数,若传入None,则不计算 IC 衰减

# 分组收益分析

QuantileReturnAnalysis(quantile=5, benchmark=None)
# 参数
  • quantile: 分组数量
  • benchmark: 基准,支持传入指数代码

# 因子收益率计算

FactorReturnAnalysis()

# 3. 构建管道

首先需要实例化引擎,例如:

engine = FactorAnalysisEngine()

引擎通过append方法接受一个tuple,格式为(name, processor),name不能重复。如需添加多个处理器或分析器,请逐步添加,例如:

# 数据处理
engine.append(('winzorization-mad', Winzorization(method='mad')))
engine.append(('normalization', Normalization()))
# IC分析
engine.append(('rank_ic_analysis', ICAnalysis(rank_ic=True)))

# 4. 执行计算

通过analysis传入因子值等数据

engine.analysis(factor_data, returns, ascending=False, periods=1, keep_preprocess_result=False)
# 参数
  • factor_data: 因子值,类型为pd.DataFrame,index 为datetime,columns 为 order_book_id
  • returns: 收益率数据,可输入daily或pd.DataFrame。如选daily,则函数自动根据get_price_change_rate查询对应 id 的日涨跌幅数据(仅支持股票和指数);如上传pd.DataFrame,其index和columns应和factor_data的相同。
    • 引擎将使用 T 期因子值和 T+1 期收益率进行计算,如果希望使用 T+N 期收益率,用户可自行 shift 收益率数据
  • ascending: 因子值排序方向,True表示从小到大排序;False则从大到小排序
  • periods: 调仓周期,即累计收益率的周期。 int 或者list,例如[1,5,10],最多三个周期。
  • keep_preprocess_result: 是否保存预处理数据结果,True表示保存。
# 返回: dict

key 为每个分析器的名字,value 为该分析器的分析结果,具体接口和字段见下文。

# ICAnalysis 结果

返回ICAnalysisResult 类型的对象,包含以下接口:

  • ic: 各期 IC 值;
  • rolling(window=12): 计算 IC 滚动均值,可通过window指定窗口数量,最多 20 期 ;
  • summary(): 计算 IC 统计指标,返回dict类型,计算结果包含以下字段:
    • mean: IC 序列的均值
    • std: IC 序列的标准差
    • positive: IC 为正的个数
    • negative: IC 为负的个数
    • significanse: IC 显著性水平(p 值小于 0.01 的占比)
    • sig_positive: 正 IC 显著性水平
    • sig_negative: 负 IC 显著性水平
    • t_value: 多期 IC 值分布作 T 检验所得到的 T 统计量
    • p_value: 多期 IC 值分布作 T 检验所得到的 P 值
    • skew: IC 序列的偏度
    • kurtosis: IC 序列的峰度
    • ir: IC 序列的均值与标准差的比值
  • ic_decay: ic_decay 序列
  • ic_industry_distribute: IC 行业分布
  • show(): 绘制分析结果

# QuantileReturnAnalysis 结果

返回 QuantileReturnAnalysisResult 类型的对象,包含以下接口:

  • quantile_returns: 各期分组累计收益率序列
  • quantile_turnover: 各期分组换手率
  • top_minus_bottom_returns: 做多第一组做空最后一组的收益率序列
  • quantile_detail:各期分组情况
  • benchmark_return: 各期基准收益率序列
  • show(): 绘制分析结果

# FactorReturnAnalysis 结果

返回 FactorReturnAnalysisResult 类型的对象,包含以下接口:

  • factor_returns: 因子累计收益率
  • max_drawdown(): 最大回撤值
  • std(): 因子收益率波动率
  • show(): 绘制分析结果

# 数据处理结果

当keep_preprocess_result为True时,将按照因子预处理的顺序和名称依次返回因子结果,例如因子管道构建代码为:

engine.append(('winzorization-mad', Winzorization(method='mad')))
engine.append(('normalization', Normalization()))

返回dict的key中会包含winzorization-mad和normalization。

# 使用示例

  • 基于沪深 300 股票池,计算 20210101 - 20211101 的 pe 因子
import pandas as pd
import datetime
from rqfactor import *
import rqdatac
rqdatac.init()
d1 = '20210101'
d2 = '20211101'
f = Factor('pe_ratio_ttm')
ids = rqdatac.index_components('000300.XSHG',d1)
df = execute_factor(f,ids,d1,d2)
  • 将每日 14:00 的分钟 close 数据合成为新的收益率数据
price = rqdatac.get_price(ids,d1,d2,frequency='1m',fields='close',expect_df=False)
target = datetime.time(14, 0)
mask = price.index.get_level_values('datetime').time == target
returns = price[mask].pct_change()
returns.index = pd.DatetimeIndex(returns.index.date)
  • 构建管道,并将因子值和收益率传入分析器中进行计算
engine = FactorAnalysisEngine()
engine.append(('winzorization-mad', Winzorization(method='mad')))
engine.append(('rank_ic_analysis', ICAnalysis(rank_ic=True, industry_classification='sws')))
result = engine.analysis(df, returns, ascending=True, periods=1, keep_preprocess_result=True)
result['rank_ic_analysis'].summary()
# Out:
#               P_1
# mean	        0.007487
# std	        0.243561
# positive	  100.000000
# negative	  99.000000
# significance	0.628141
# sig_positive	0.301508
# sig_negative	0.316583
# t_stat  	0.433625
# p_value	  0.665033
# skew	        0.067769
# kurtosis  	-0.774880
# ir	        0.030739
  • 绘制 IC 结果图
result['rank_ic_analysis'].show()

ic结果

ic行业分布结果

# 量价因子 范例 1

from rqfactor import *
from rqfactor.extension import *
from rqfactor.notebook import *
import rqdatac
rqdatac.init()
VWAP = Factor('total_turnover') / Factor('volume')
f = (RANK((VWAP - Factor('close'))) / RANK((VWAP + Factor('close'))))

# 量价因子 范例 2

from rqfactor import *
from rqfactor.extension import *
from rqfactor.notebook import *
import rqdatac
import numpy as np
import pandas as pd
rqdatac.init()
#定义自定义因子
def buy_volume(order_book_ids,start_date,end_date):
    return rqdatac.get_capital_flow(order_book_ids,start_date,end_date).buy_volume.unstack('order_book_id').reindex(columns=order_book_ids,index =pd.to_datetime(rqdatac.get_trading_dates(start_date,end_date)))
def sell_volume(order_book_ids,start_date,end_date):
    return rqdatac.get_capital_flow(order_book_ids,start_date,end_date).sell_volume.unstack('order_book_id').reindex(columns=order_book_ids,index =pd.to_datetime(rqdatac.get_trading_dates(start_date,end_date)))
BUY_VOLUME = UserDefinedLeafFactor('BUY_VOLUME',buy_volume)
SELL_VOLUME = UserDefinedLeafFactor('SELL_VOLUME',sell_volume)
f = DELTA(MA(BUY_VOLUME-SELL_VOLUME,13)/IF(MA(ABS(BUY_VOLUME-SELL_VOLUME),13) !=0,MA(ABS(BUY_VOLUME-SELL_VOLUME),13),np.nan),3)
d1='20190101'
d2='20200101'
df = execute_factor(f,rqdatac.index_components('000300.XSHG', d1),d1,d2)
#实例化引擎
engine=FactorAnalysisEngine()
#构建管道,对因子进行预处理
engine.append(('neutralization', Neutralization(industry='citics_2019', style_factors=['size','beta','earnings_yield','growth','liquidity','leverage','book_to_price','residual_volatility','non_linear_size'])))
#构建管道,添加因子分析器
engine.append(('rank_ic_analysis', ICAnalysis(rank_ic=True, industry_classification='sws',max_decay=20)))
engine.append(('quantile', QuantileReturnAnalysis(quantile=5, benchmark=None)))
engine.append(('return',FactorReturnAnalysis()))
#调仓周期为1,3,5
result = engine.analysis(df, 'daily', ascending=True, periods=[1,3,5], keep_preprocess_result=True)
  • 查看因子 IC 分析结果
In[]:
result['rank_ic_analysis'].summary()
Out[]:
                 P_1    	  P_3	        P_5
mean	        0.002531	  -0.005552	  -0.012799
std	          0.062977	  0.064005	  0.060862
positive	    117.000000	118.000000	107.000000
negative	    127.000000	126.000000	137.000000
significance	0.024590	  0.040984	  0.036885
sig_positive	0.012295	  0.004098	  0.008197
sig_negative	0.008197	  0.024590	  0.008197
t_stat	      0.627707	  -1.354970	  -3.284878
p_value	      0.530785	  0.176685	  0.001171
skew	        0.223259	  -0.401776	  -0.088231
kurtosis	    0.176964	  0.414680	  -0.099484
ir	          0.040185	  -0.086743	  -0.210293
  • 绘制因子分组收益率结果

result['quantile'].show()

分组多空收益率结果
分组换手率结果-P_1
分组累积收益率结果-P_1
分组换手率结果-P_3
分组累积收益率结果-P_3
分组换手率结果-P_5
分组累积收益率结果-P_5

  • 绘制因子收益率结果

result['return'].show()

因子收益率结果

# 月度因子(自然月)范例

  • 财务因子比较偏向价值投资,一般持有期会相对较长,这里采用以自然月为收益区间验证财务因子
from rqfactor import *
from rqdatac import *
import pandas as pd
init()
#因子定义
f = RANK((Factor('net_profit_parent_company_ttm_0')/Factor('equity_parent_company_ttm_0')) /(Factor('net_profit_parent_company_ttm_1')/Factor('equity_parent_company_ttm_1')), 'first', True)
d1 = '20210101'
d2 = '20211201'
ids= index_components('000300.XSHG',d1)
#因子数据
df = execute_factor(f,ids,d1,d2)
df = df.resample('BM').last()
#合成每个自然月的收益率数据
returns=get_price_change_rate(ids, start_date=d1, end_date=d2, expect_df=True)+1
#为了使用resample能更便捷聚合收益率数据,这里直接将收益率数据index平移一个交易日
returns.index=get_trading_dates(get_previous_trading_date(returns.index[0]), get_previous_trading_date(returns.index[-1]), market='cn')
returns.columns.name=''
returns.index=pd.DatetimeIndex(returns.index)
#returns.index平移后,聚合的为当月第二个交易日到下一个月第一个交易日的收益率数据
returns=returns.resample('BM').prod()-1
returns.index=pd.DatetimeIndex(returns.index.date)
returns.columns.name=''
# 构建管道,并将因子值和收益率传入分析器中进行计算
engine = FactorAnalysisEngine()
# engine.append(('winzorization-mad', Winzorization(method='mad')))
engine.append(('rank_ic_analysis', ICAnalysis(rank_ic=True, industry_classification='sws',max_decay=10)))
engine.append(('QuantileReturnAnalysis', QuantileReturnAnalysis(quantile=10, benchmark='000300.XSHG')))
result = engine.analysis(df, returns, ascending=True, periods=1, keep_preprocess_result=True)
  • 查看 IC 分析结果及分组情况
In[]:
result['rank_ic_analysis'].summary()
Out[]:
                   P_1
mean         -0.006272
std           0.106604
positive      7.000000
negative      5.000000
significance  0.333333
sig_positive  0.083333
sig_negative  0.083333
t_stat       -0.203807
p_value       0.842226
skew          0.281141
kurtosis      0.418097
ir           -0.058834
In[]:
result['QuantileReturnAnalysis'].quantile_detail
Out[]:
order_book_id 600183.XSHG 603658.XSHG 601319.XSHG 600637.XSHG 002179.XSHE  \
datetime
2021-01-29            NaN         NaN         NaN         NaN         NaN
2021-02-26             q5          q3          q4          q6          q7
2021-03-31             q5          q3          q4          q6          q7
2021-04-30             q3          q3          q4          q6          q6
2021-05-31             q7          q2          q8          q4          q9
2021-06-30             q7          q2          q8          q4          q9
2021-07-30             q7          q2          q8          q4          q9
2021-08-31             q7          q2          q8          q4          q9
2021-09-30             q9          q2          q7          q2          q3
2021-10-29             q9          q2          q7          q2          q3
2021-11-30             q9          q3          q2          q3          q6
2021-12-31             q9          q3          q2          q3          q6
order_book_id 002050.XSHE 600660.XSHG 600176.XSHG 601877.XSHG 000157.XSHE  \
datetime
2021-01-29            NaN         NaN         NaN         NaN         NaN
2021-02-26             q6          q3          q4          q5          q7
2021-03-31             q6          q3          q4          q5          q7
2021-04-30             q4          q8          q9          q5          q7
2021-05-31             q7          q9         q10          q2          q8
2021-06-30             q7          q9         q10          q2          q8
2021-07-30             q7          q9         q10          q2          q8
2021-08-31             q7          q9         q10          q2          q8
2021-09-30             q5          q8         q10          q5          q2
2021-10-29             q5          q8         q10          q5          q2
2021-11-30             q5          q5         q10          q3          q2
2021-12-31             q5          q5         q10          q3          q2
order_book_id  ... 002311.XSHE 601398.XSHG 601111.XSHG 002384.XSHE  \
datetime       ...
2021-01-29     ...         NaN         NaN         NaN         NaN
2021-02-26     ...          q6          q4         q10          q1
2021-03-31     ...          q6          q4         q10          q1
2021-04-30     ...          q6          q7         q10          q1
2021-05-31     ...          q7          q4          q9          q2
2021-06-30     ...          q7          q4          q9          q2
2021-07-30     ...          q7          q4          q9          q2
2021-08-31     ...          q2          q4          q9          q2
2021-09-30     ...          q3          q6          q1          q3
2021-10-29     ...          q3          q6          q1          q3
2021-11-30     ...          q1          q6         q10          q8
2021-12-31     ...          q1          q6         q10          q8
order_book_id 002594.XSHE 600690.XSHG 002600.XSHE 000661.XSHE 600019.XSHG  \
datetime
2021-01-29            NaN         NaN         NaN         NaN         NaN
2021-02-26            q10          q8          q1          q7          q8
2021-03-31            q10          q8          q1          q7          q8
2021-04-30             q9          q9         q10          q5          q8
2021-05-31             q2          q7          q8          q6         q10
2021-06-30             q2          q7          q8          q6         q10
2021-07-30             q2          q7          q8          q6         q10
2021-08-31             q2          q7          q8          q6         q10
2021-09-30             q1          q8          q1          q5         q10
2021-10-29             q1          q8          q1          q5         q10
2021-11-30             q1          q2          q6          q5          q9
2021-12-31             q1          q2          q6          q5          q9
order_book_id 002008.XSHE
datetime
2021-01-29            NaN
2021-02-26             q9
2021-03-31             q9
2021-04-30             q2
2021-05-31             q9
2021-06-30             q9
2021-07-30             q9
2021-08-31             q9
2021-09-30             q6
2021-10-29             q6
2021-11-30             q9
2021-12-31             q9
[12 rows x 300 columns]
  • 绘制 IC 分析结果

result['rank_ic_analysis'].show()

因子IC分析结果

# F-Score 因子范例

F-Score 因子出自 Piotroski 的论文《Value Investing: The Use of Historical Financial Statement Information to Separate Winners from Losers》,主要从三个维度(profitability、financial leverage/liquidity、operating efficiency)来衡量公司的基本面状况。作者选用了九个好实施的指标,并且每个指标使用“好”或“坏”评判该公司在该指标上的表现。F-Score 因子是这九个指标的加总。

指标 打分方式
资产收益率 大于零为 1,否则为 0
资产收益率变化率 大于零为 1,否则为 0
经营活动产生的现金流比总资产 大于零为 1,否则为 0
应计收益率 大于零为 0,否则为 1
长期负债率变化 大于零为 0,否则为 1
流动比率变化 大于零为 0,否则为 1
股票是否增发 是为 0,否则为 1
毛利率变化 大于零为 1,否则为 0
资产周转率 大于零为 1,否则为 0
from rqfactor import *
from rqfactor.extension import *
from rqfactor.notebook import *
import rqdatac as rq
import pandas as pd
rq.init()
import numpy as np
from rqfactor.engine_v2 import execute_factor
#自定义算子,使得因子值大于0时返回1,否则返回0
def fillter(df):
    df[df>0]=1
    df[df<=0]=0
    df=df.fillna(0)
    return df
def Fillter(f):
    return UnaryCrossSectionalFactor(fillter, f)
#自定义算子,使得因子值大于0时返回0,否则返回1
def fillter_1(df):
    df[df<0]=1
    df[df>=0]=0
    df=df.fillna(0)
    return df
def Fillter_1(f):
    return UnaryCrossSectionalFactor(fillter_1, f)
##构建因子
#1.ROA因子,大于0得1分,否则0分
f1 = Fillter(Factor('return_on_asset_ttm'))
#2.Δroa因子,大于0得1分,否则0分
f2 = Fillter(Factor('net_profit_mrq_0')/Factor('total_assets_mrq_0')-Factor('net_profit_mrq_3')/Factor('total_assets_mrq_3'))
#3.cfoa因子,大于0得1分,否则0分
f3 = Fillter(Factor('cash_flow_from_operating_activities_ttm_0')/Factor('total_assets_ttm_0'))
#4.应计利润,小于0得1分,否则0分
f4 = Fillter_1((Factor('profit_from_operation_ttm_0')-Factor('cash_flow_from_operating_activities_ttm_0'))/Factor('total_assets_ttm_0'))
#5.ΔLEVER,小于0得1分,否则0分,需对银行类别进行处理
def lever(order_book_ids, start_date, end_date):
    trading_dates=rq.get_trading_dates(start_date, end_date, market='cn')
    a=rq.get_factor(order_book_ids,'non_current_liabilities_mrq_0',start_date, end_date)['non_current_liabilities_mrq_0']
    b=rq.get_factor(order_book_ids,'total_assets_mrq_0',start_date, end_date)['total_assets_mrq_0']
    lever=a/b
    lever=lever.unstack('order_book_id')
    lever.columns.name=''
    lever.index.name=''
    lever=lever.reset_index(drop = False)
    lever.index=lever[''].tolist()
    lever.index=trading_dates
    lever=lever.drop(columns='')
    for key,value in lever.iteritems():
        if key in rq.get_industry('银行', source='citics', date=end_date):
            lever[key]=rq.get_factor(key,'deposits',start_date, end_date).unstack('order_book_id')['deposits']\
                       +rq.get_factor(key,'bond_payable',start_date, end_date).unstack('order_book_id')['bond_payable']\
                       +rq.get_factor(key,'borrowings_from_central_banks', start_date, end_date).unstack('order_book_id')['borrowings_from_central_banks']
    lever.index = pd.DatetimeIndex(lever.index)
    return lever
LEVER=UserDefinedLeafFactor('LEVER', lever)
f5=Fillter_1(LEVER-REF(LEVER, 252))
#6.ΔLIQUID,大于0得1分,否则0分
def liquid(order_book_ids, start_date, end_date):
    trading_dates=rq.get_trading_dates(start_date, end_date, market='cn')
    a=rq.get_factor(order_book_ids,'current_assets',start_date, end_date).fillna(method='pad')
    b=rq.get_factor(order_book_ids,'current_liabilities',start_date, end_date).fillna(method='pad')
    liquid=a['current_assets']/b['current_liabilities']
    liquid=liquid.unstack('order_book_id')
    liquid.columns.name=''
    liquid.index.name=''
    liquid=liquid.reset_index(drop = False)
    liquid.index=liquid[''].tolist()
    liquid.index=trading_dates
    liquid=liquid.drop(columns='')
    for key,value in liquid.iteritems():
        bf_obi=rq.get_industry('银行', source='citics', date=end_date)+rq.get_industry('非银行金融', source='citics', date=end_date)
        a=['cash_equivalent','deposits_of_interbank','precious_metals','lend_capital',
           'financial_asset_held_for_trading','derivative_financial_assets','resale_financial_assets',
            'interest_receivable','loans_advances_to_customers','financial_asset_available_for_sale'
              'financial_asset_hold_to_maturity','loan_account_receivables']
        b=['borrowings_from_central_banks','deposits_of_interbank','borrowings_capital','financial_liabilities',
              'derivative_financial_liabilities','buy_back_security_proceeds','deposits','payroll_payable',
                'tax_payable','dividend_payable']
        if key in bf_obi:
            liquid[key]=(rq.get_factor(key,a,start_date,end_date).sum(axis=1)/rq.get_factor(key,b,start_date,end_date).sum(axis=1)).unstack('order_book_id')
    liquid.index=pd.DatetimeIndex(liquid.index)
    return liquid
LIQUID=UserDefinedLeafFactor('LIQUID', liquid)
f6 = Fillter(LIQUID-REF(LIQUID,252))
#7.EQ_OFFER,过去一年是否增发或配售新股,没有增发得1分,否则为0
def eq_offer(order_book_ids, start_date, end_date):
    trading_dates=rq.get_trading_dates(start_date, end_date, market='cn')
    c=pd.DataFrame(columns=order_book_ids,index=trading_dates)
    for i in trading_dates:
        pp=rq.get_private_placement(order_book_ids, start_date=rq.get_previous_trading_date(i,252,market='cn'),
                                 end_date=i, progress='complete',issue_type='private', market='cn')
        for b in pp.index.get_level_values('order_book_id').values:
            c.loc[i, b] = 0
    for i in trading_dates:
        pp=rq.get_private_placement(order_book_ids, start_date=rq.get_previous_trading_date(i,252,market='cn'),
                                 end_date=i, progress='complete',issue_type='private', market='cn')
        for b in pp.index.get_level_values('order_book_id').values:
            c.loc[i, b] = 0
    c=c.fillna(1)
    c.index = pd.DatetimeIndex(c.index)
    return c
f7 = UserDefinedLeafFactor('EQ_OFFER', eq_offer) #自定义因子
#8.ΔMARGIN因子,大于0得1分,否则0分
f8 = Fillter((Factor('operating_revenue_mrq_0')-Factor('total_expense_mrq_0'))/Factor('operating_revenue_mrq_0')\
     -(Factor('operating_revenue_mrq_3')-Factor('total_expense_mrq_3'))/Factor('operating_revenue_mrq_3'))
#9.ΔTURN:最新报告期资产周转率-上年同期资产周转率,大于0得1分,否则0分
f9 =Fillter(Factor('operating_revenue_mrq_0') / Factor('total_assets_mrq_0')-Factor('operating_revenue_mrq_3') / Factor('total_assets_mrq_3'))
f=f1+f2+f3+f4+f5+f6+f7+f8+f9
#检验因子
#print(execute_factor(f, rq.index_components('000300.XSHG', '20180201'), '20180101', '20180201'))
df=execute_factor(f, rq.index_components('000300.XSHG','20150101'), '20150101', '20200101')
engine = FactorAnalysisEngine()
engine.append(('neutralization',Neutralization(industry='sws',style_factors=['size','beta','momentum','growth','book_to_price','residual_volatility','non_linear_size'])))
engine.append(('rank_ic_analysis', ICAnalysis(rank_ic=False, industry_classification='sws')))
engine.append(('QuantileReturnAnalysis', QuantileReturnAnalysis(quantile=3, benchmark='000300.XSHG')))
result = engine.analysis(df, 'daily', ascending=False, periods=22, keep_preprocess_result=True)
# 绘制 IC 结果图
result['rank_ic_analysis'].show()
result['QuantileReturnAnalysis'].show()

IC分析结果
因子分组收益率结果-P-1
因子分组收益率结果-P-2
因子分组收益率结果-P-3

Last Updated: 5/24/2024, 10:05:09 AM

← 因子开发指南