![5be098479452313459bdf53f423bbb4d.png](https://i-blog.csdnimg.cn/blog_migrate/a17ea46e6fb9f09d8320c38abfe88961.jpeg)
1. 叨叨念 -- 当我们讲单因子分析的时候,意味着什么?
首先是很内疚,给 QUANTAXIS
pr 的 QAFactor
没有经过仔细的 review 和测试就急匆匆地上线,很是让 QA 作者抓狂,给所有因为更新 QA 而搞崩服务的用户道歉,以后类似地事情一定不能再发生了。
然后回到 QAFactor
这个模块本身,因为最开始写地时候,笔者就希望能汲取 alphalens
和 jqfactor_analyzer
两者之长,不然完全 copy 两者的代码,也没有必要再去发个新的单因子分析模块了。在实际去写这个模块的时候,因为过于求全责备,于是同样一段代码,可能可以一句话解决问题,但因为有特例存在,于是不得不去对代码修修补补,考虑这种极端情况,考虑那种特殊场景,于是代码也不得不加入各种情况的考虑,导致往往一个细节耗费了很多时间,但大框架其实也仅仅是完成部分。这里也算是一种经验教训吧,如果想要快速去实现一个功能,细节固然需要考虑,但是优先级肯定不是最高的,先把大框架搭起来之后,然后往框架里填充内容即可。
最后回到单因子分析模块本身,当我们谈论单因子分析的时候,意味着什么?其实就笔者个人体验而言,万物皆因子,不过是不同的因子对资产标的的影响不同而已。但是,各种现实条件的影响,譬如数据量,譬如计算力,譬如主观偏好等,我们希望的是能找到真正去与实际资产波动有相关 (无论是正相关亦或者负相关) 的因子,而与资产标的无关的因子,完全可以当作噪音,需要我们去进行过滤。
回到股票上来,按照多因子理论,股票价格可以用对股价有实际解释力的因子进行回归得到,一个简单的线性回归形式
两种因子模型,在单因子分析模型中都应该实现,譬如,直接通过因子暴露和股价的收益率,通过回归,可以得到相应的回归系数,也就是 IC, 而通过对因子进行 quantize (分位处理,譬如5 等分,10 等分或者特殊的分位区间处理),对于高分位与低分位的因子分别做多和做空,构建零投资组合,可以计算相应的因子溢价,之后可以计算因子暴露。当然,从笔者的理解而言,构建多空组合,从收益分析已经可以很直观看出这个因子对于收益的贡献了。
下面,笔者将从最简单的因子处理开始,对单因子分析的所有流程做一个概述,并针对实践中某些量价因子处理讲讲笔者的思考与处理方式。
2. 万物之始 -- 因子产生
在正式去开始因子分析的时候,首先需要明确,什么是因子?如何得到因子?从笔者观点而言,因子就是投资者认为会对资产标的价格产生影响的因素。为了得到因子,需要针对这种因素进行量化和建模。最简单的因子获取方式其实就是通过量价,或者股票基本面数据得到因子。而某些因子,譬如宏观经济对于股价的影响,譬如新闻媒体,股评社区的情绪因子,其暴露并不那么直观,一方面,这需要投资者对相应的因素更为细致的处理,包括分词处理,情感分析等,另一方面,因子暴露不能直接获取,可以通过因子溢价进行回归得到因子暴露。
简单起见,笔者这里分别用 QUANTAXIS
保存下来的基本面数据和量价数据,构建不同级别 (周、季级别) 的因子[^1],并就其中可能会遇到的一些问题和处理方式加以说明,其中一些处理方式来自笔者搜寻的资料以及自己的思考,可能会有些谬误,如果有问题,欢迎留言指正。
相比之前,现在的量化投资比之前红火了很多,很多量化平台,包括聚宽、掘金、米筐等都有很成熟的量化数据和分析框架给到了用户,如果只是想简单试试因子效果,不妨直接去他们的网站去看看社区的一些分享和他们网站的一些示例。当然,从笔者角度而言,高级的封装固然简便了用户的使用和学习成本,但是相应处理细节的缺失,对于投资者的理解和分析都是负面影响。有鉴于此,笔者不会直接使用他们的分析模块,除了数据获取,其他的分析模块,都在本地完成。
笔者这里主要采用了 QUANTAXIS
整理的数据,这些数据都是来自通达信的数据,包括基本的量价数据、财务数据等,而类似行业分类,公司上市时间等数据,笔者直接使用了聚宽本地的数据获取 sdk,之后的分析,主要使用优秀的数据处理分析模块 pandas
。
2.1 因子股票池选择
不同行业的因子会表现出不同的特征,譬如房地产的行业特征决定了其存货会比较高,而某些行业,譬如白酒行业,则会表现出比较明显的季节性因素的。同时,从因子的极值处理,标准化处理等方面,针对行业进行分别处理无疑是更加合理的做法。因此,笔者直接直接选取了通达信的白酒概念板块所有股票进行分析。
需要注意的是,笔者这里的处理是比较粗糙的,因为 A 股很多公司会随着经济形势的改变,或者被借壳等影响,其主营会改变,导致去行业分类也在不同历史时期有不同的值。如果读者朋友们希望去更细节地研究股票的行业影响,建议按照历史时期,上市公司主营收入对公司进行更具体的行业分类。在QAFactor
的data.py
中,有根据不同交易日,去查询上市公司的行业分类代码,感兴趣的读者可以自行查看。
import pandas as pd
import QUANTAXIS as QA
code_list = QA.QA_fetch_stock_block_adv().get_block("白酒").index.get_level_values("code").tolist()
2.2 不同周期级别因子
需要注意的是,由于停牌等因素影响,当对股票池所有股票进行大级别周期采样的时候,为了避免出现时间戳不一致的情况,需要对采样数据做特殊处理,具体参加下面说明。
1. 季线级别因子
由于公司财报往往是按季度进行发布的,如果要使用公司的财务因子,只能按照季度去进行处理,笔者这里直接使用 ROE
数据,一方面是数据获取比较容易,另一方面,其反应公司的盈利能力,比较受持价投理念的投资者欢迎。
注意,这里的数据都是本地数据,读者如果想尝试,需要先自行安装QUANTAXIS
并将数据存储到本地数据库,具体做法可以直接参照 关于QUANTAXIS。 此外,QUANTAXIS
支持的基本面数据目前有三百多,具体可以参阅 QUANTAXIS 财务指标
start_date = '2010-01-01'
end_date = '2019-09-30'
df_finance = QA.QA_fetch_financial_report_adv(code=code_list, start=start_date, end=end_date).data
factor = df_finance['ROE']
2. 周线级别因子
简单起见,同时为了之后说明某些均线类策略的因子处理,笔者这里直接使用 KDJ
作为测试。
- 简单而言,周线处理,可以通过获取日线数据,对日线数据进行采样,转换为周线级别数据,之后对相应的股价数据进行 KDJ 技术指标计算,就可以得到周线级别 KDJ 值。
- 由于股票停牌,节假日等因素影响,
resample
处理的时间戳会出现一些异常值,不利于时间截面上的因子分析。因此,这里使用指数数据作为基准,对周线数据进行时间戳的统一处理。
# 因子股票池
code_list = QA.QA_fetch_stock_block_adv().get_block(
"白酒").index.get_level_values("code").tolist()
# 数据时间范围
start_date = '2018-01-01'
end_date = '2019-09-30'
# 周线数据
stock_data = QA.QA_fetch_stock_day_adv(code=code_list,
start=start_date,
end=end_date).to_qfq().resample("w")
index_data = QA.QA_fetch_index_day_adv(code='000001',
start=start_date,
end=end_date).resample("w")
# 数据预处理
# 日期索引处理
stock_data = stock_data.unstack().ffill().reindex(
index_data.unstack().index).stack()
# 原始因子产生
kdj = stock_data.groupby("code").apply(
QA.QAIndicator.QA_indicator_KDJ).droplevel(level=-1)
k_value = kdj["KDJ_K"]
d_value = kdj["KDJ_D"]
j_value = kdj["KDJ_J"]
</