在下文中,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 | 成交笔数 |
财务因子
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
时,使用因子值计算 icindustry_classification
: 分组依据,None
代表不计算 IC 行业分布;可输入sws
或citics_2019
,仅支持股票因子;对于股票之外的资产类型,可传入自定义分组pd.Series
ordict
,其中index
或key
为资产 idmax_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()
# 量价因子 范例 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()
- 绘制因子收益率结果
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()
# 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()
← 因子开发指南