投资有风险,瞎编策略风险也不小啊。

基于多因子选股模型打分法选股与动量对冲的投资策略

摘要:本文第一部分叙述了文章背景及准备工作,而第二部分详述了笔者寻找并基于多因子选股模型进行打分法选股的投资策略,并在第三部分讲解了基于通道突破思维动态调整做空比率的股指期货对冲方案。最后对附加问题进行了简略的回答,并总结全文。

0x01 绪论

1.1 论文背景及意义

本学期我选修了《金融数学与金融衍生品市场》这门通识课,在国信期货诸多专家的讲解下了解了许多与金融市场相关的知识,也粗略学到了一些量化投资的方法。量化投资,顾名思义,即通过数量化方式及计算机程序化建模,以绝对理性代替人为主观判断制定稳定收益投资策略的方法。近几十年来,中国金融市场波澜起伏,量化投资也渐入佳境。当今时代,人人都需要学会理财。而本课程也为笔者开启了一扇全新的大门。本文即以往年数据为基础,借助基于多因子选股思想的打分方法等手段建立模型进行投资模拟,并以股指期货进行动量对冲相辅,初步对量化投资思维进行学习和实践。

1.2 预备工作

初遇本题目时,事实上我一头雾水,只感觉整个题目是十分难以完成的,原来对代码能力与建模思维有所要求不只是说说而已。但在经过十余天的努力后,我发现整个流程较实际相比,难度其实已降低很多。光是无需考虑印花税与手续费这一点就让我的代码实现精简了不少。新的一年到来之前,我终于完成了整个策略的代码实现。过程略有粗糙,但第一次用自己的代码成功分析金融数据,心中难免有所激动。下面我将着眼于准备工作(数据来源、实验年份及其他)进行叙述:

首当其冲的难点便是数据来源。在QQ群里,老师和同学们都很热心,以Excel形式公布了许多往年数据,然其均不适做代码分析之原料。在一番搜索后,我参考[1]获得许多接口,但一一比较后我选择了聚宽(JQData)作为本次实验的数据来源。原因不外乎三点:免费;数据种类全面,规模庞大;接口方法简单明了(此处有伏笔,后提)。但它也有一个巨大的缺点:试用用户每天只能获取100万条数据,这也使得整个DEBUG以及回测的流程时长增加了不少。我也曾想过使用Wind数据,但高昂的费用等让我望而却步。总之,JQData[2]给予了我很大的帮助,在此进行感谢。

在选择实验年份的考虑上,我本准备仅对2019年(是随意选择的一年)进行测试,但后我发现2018年的沪深300指数整体呈下跌趋势,与2019的上升形成鲜明的对比。于是我对2018与2019的沪深300股均进行了分析并对策略进行了微小改进。

在编程语言的选择上,策略实现均基于Python 3.7.9。原因是我仅对 Python, C++ 相对熟练,而 Python 显然是再好不过的选择。在此,我将实验代码使用到的第三方库一一列举:jqdatasdk, matplotlib, scipy, numpy。下面对我的策略流程进行详述。

0x02 选股方案研究

2.1 策略选择

2.1.1 策略来源

初期,我通过课内[3]了解到许多不同的选股策略:单因子选股、多因子选股、SVM随机森林等。但显然非线性的策略并不适合我这个机器学习小白,综合考量之下,我找到了论文[4],通览论文后在其结论基础上建立模型自主编写代码;而在选股比例的确定上,我参考了[5]及其代码部分,在它的基础之上加以改动写出函数 get_partial() 作为投资组合比例的确定方案。最终我通过多因子模型进行等权重打分法选择股票组合,并以马科维茨投资组合理论为基计算协方差找到有效前沿,在该条件下确定方差最小的组合对各股票占比进行确定。

2.1.2 多因子选股打分方案

多因子模型,即通过对多个解释变量的历史表现进行打分,选取综合分数较高的股票。其弊端在于选取因子稳定性、计算周期难以确定,因子间相关性差异易造成影响等。而打分法是对股票各个有效因子进行评分,根据一定权重加权获取总分以筛选股票的方法。

本文参考[4]从估值、成长、财务质量、行情因素中选取出的最有效的5个线性因子(市盈率 PE(TTM)、营业收入同比增长率、净资产收益率、月度区间日均涨跌幅、换手率)采用综合 Z-score 模型进行打分,对单个因子分别从低到高进行排序,排在第i位则加i分。最后等权进行分数的总和,选取总分最高的 k 只股票作为股票组合。

其中,因子表现选取的周期为选股前 22 个交易日;而投资比例的确定以前一个自然年的数据作为基准。

2.2 实现过程

确定交易年份,自当年第一个交易日开始买入,于最后一个交易日平仓。以收盘价为买卖基准,于每个自然月的第一个交易日和第 n/2 个交易日进行交易,记录每天的沪深300指数与本策略组合之走势情况。之所以每个月只有两天进行操作,其一原因是每天进行操作对我来说过于理想化;二是每天操作会导致手续费过高;三在于JQData每天只能进行 100 万次查询的限制。由于不考虑交易手续费,我在代码中直接采用:当天先直接平仓已有股票组合,再满仓新组合的方式进行模拟交易。

本部分代码大致流程如下:

  1. 调用 sell_ 函数卖出已有股票组合。
  2. 以当天沪深300成分股为股票池,调用 select 函数选择新的股票组合。
  3. 通过 buy_ 确定股票比例并模拟买入操作。
  4. 在月份的循环中记录每一天的股票组合、指数走势情况。(与(1),(2),(3)在同一个循环中进行)
  5. 输出结果。

在实现代码的过程中,我遇到了不少的问题。例如沪深300成分股的确定及更换、模拟买卖操作的实现等。但遇到的最大问题是,在多次模拟回测中发现买卖价格与股票代码不匹配。经过多次动态调试及验算,我发现聚宽接口的返回顺序并不是与输入顺序匹配的,在调用不同接口时返回的顺序也可能不同。基于此,代码中每次都用 stock.sort() 和单只股票分别查询的方法避免顺序混乱。程序结果各个输出量的关系在大概观察后也相对吻合。

2.3 数据分析

此处给出对2019年的模拟截图证明笔者本地的运行结果有效:

本部分将对18、19年的数据进行简单分析。在一番折腾后,我借助 Python 的第三方库 matplotlib 画出了策略净值走势图:

2018年 沪深300指数 本策略


全年收益率 -25.31% -32.42%

最大回撤 31.88% 47.75%

2019年 沪深300指数 本策略


全年收益率 36.07% 72.15%

最大回撤 13.49% 26.45%

我们可以看到策略在全盘上涨的情况下是远远胜过沪深300指数的,但在熊市的情况下表现则不佳。同时我们发现策略的最大回撤都较指数更大,这说明我们的策略是不够稳定的。总体上来说,本策略风险较大,并不够符合我们的初衷”获取稳定收益”,虽然在 2019 年的表现很好,但总体上也只能说是差强人意。

0x03 对冲策略设计

3.1 对冲背景

为什么需要对冲?我认为,在对市场信息了解有限的情况下,采用对冲的方法降低组合风险是十分有必要的。或许不对冲能够获得更多的收益,但亏损的风险也是十分之大的。如果选择了现货做多期货做空的方式对冲,在整体保证alpha收益的情况下,风险就将大大降低。我们上面所做的策略并没有达到”获取稳定收益”的目标,这时我们就可以利用对冲的手段来降低系统性风险。而股指期货的多空双向交易属性就给予了我们一个对冲的平台。现货做多,期货做空,这显然是一个较好的做空思路。

3.2 策略选择

3.2.1 策略来源

为了降低代码编写难度以及更好地对比对冲前后的风险,我并未重新寻找选股策略,而是在前一部分的基础上进行对冲。

在对往期课程[3][6]的回顾后,如果按照其给出的公式进行计算,我发现关键点在于如何去计算对冲期货手数。公式 $Num ={ {P * \beta_p * r } \over { F * 300 * \beta_h } }, \beta_{a}={ {Cov (r_a,r_m ) }\over { \sigma_m ^2 } }$ 的计算是我遇到的较大阻碍。但后经搜索参考[7]发现 numpy 中即有求取协方差的函数 Cov(),随后我参考[7]代码部分改动并书写了函数 get_ifs_num() 进行期货做空手数的确定。为了方便,我每个月做空一次下月的期货,并在每月中旬进行调整,在下个自然月第一个交易日平仓。

在一开始进行对冲部分编写时,我被对冲比率r所难住了,不太懂得如何根据走势作出预判来调整对冲比例,于是选择固定 r = 1.00 的策略。后来我发现这样做出的效果并不尽人意,则通过搜索找到了论文[8],参考其中的通道突破思维动量对冲方案来动态调整我的对冲比率 r。效果总体上来讲比固定 r=1.00 时要好(我认为固定r不够灵活,相当于把收益与风险都直接打了对折),但总体上仍有较大的提升空间。

3.2.2 通道突破调整做空比率

通道突破思维最早由唐奇安发明,其根本思想是趋势追踪。当实际价格超越前k天最大值时买进股票进场,低于最小值时卖出股票出场。在此我们借鉴[8]的思维,将其应用到期货市场上用以动态调整做空比率:以当前总资产价值作为追踪指标,当总价值突破前 adjust_period 天的最大值时向下调整对冲比率,反之向上调整。我认为动态调整做空比率的最大意义在于获得更多收益。

后期测试的时候对追踪策略进行了改动,将突破adjust_period天的条件改为:当日或前一个交易日占整个 adjust_period 周期的 max/min 时即调整比率,以使对冲资金与总资产的相关度更高。

在此对代码中的某些参数设置进行说明:

每次调整的系数 $up-ratio,\ down-ratio\ = \ 1.045,\ 0.965$。之所以选择这两个值是因为它们每次调整的影响不大,由于每天都要进行调整,在叠加后影响也不小。且相比起超额收益,我更关注策略整体的稳定性。1.045 * 0.965 = 1.008425,当一升一降调整后总体趋势是略微增加的,这使得做空资金稍多,风险也稍能降低。

而 $adjustperiod = 15$ 是每次交易操作后的空档期,不长不短,对动量对冲具有一定的参考价值。

实验中选取了以 75% 的资金作为现货做多资金,剩余的 25% 作为做空及机动资金。

3.3 实现过程

说明:在每月的第 1 个和第 n/2 个交易日进行交易操作,鉴于无手续费的缘故,反映到代码流程上,为了便捷即为每日按收盘价更新总资金,在两个交易操作日分别生成新的股票组合与根据当日做空比率调整做空手数。其中变量 if_money 每天仅保持当日结算价的保证金数量,多余部分保存于 available_money 中。这样的好处在于只需要 $assert\ available-money\ > = \ 0$ 即可保证当日无负债。

  1. 每月第一个交易日调用 sell_stocks 函数卖出已有股票组合。
  2. 以当天沪深300成分股为股票池,调用 select 函数选择新的股票组合。
  3. 通过 buy_stocks 确定股票比例并模拟买入操作。
  4. 通过 adjust、get_ifs_num 调整做空比例,并以 buy_if 做空期货。
  5. 在月份的循环中记录每一天的股票组合走势、指数走势、对冲比率情况,并根据期货当日结算价调整变量间的关系,确保当日无负债。(与(1),(2),(3),(4)在同一个循环中进行)
  6. 输出结果。

3.4 数据分析

首先对动态比例对冲进行说明:

我们可以看到,对冲后的策略在 2018 年的表现比沪深300指数更加优秀,足以证明该对冲策略有一定的有效性、稳定性。

然后我们对无对冲(本文第 2 部分所述)、固定对冲比率、动态调整比率进行一个对比:

可以看到,采用动态比率对冲后的最终结果总是比直接固定比例对冲的效果要好,而对冲后的风险与收益相较于无对冲时都降低了不少。但这里可以看到 2018 年最终的绝对结果仍然是亏损的,说明我选股采取的策略 alpha 超额收益表现不佳,尚待改进;同时发现在 6 月时,静态比率对冲要比动态更加优越,这里也说明我的比率调整策略存在问题。但从我这个初学者的角度上来看,其总体上的稳定性也是可观的。

而对冲比率的动态调整图也说明动态对冲是具有一定优越性的:

可以看到,当资金量呈上涨趋势的时候,对冲比率下降;反之上升。而大盘的表现也大概符合我们的期望。说明动态调整对冲比率是有效的,以期规避一部分期货空头在上涨行情下的损失。

最后以表格数据形式简单对比:

2018年 沪深300指数 不对冲 对冲(动态) 对冲(固定比率)


累计收益率 -25.31% -32.42% -9.77% -11.13%

最大回撤 31.88% 47.75% 35.34% 31.34%

2019年 沪深300指数 不对冲 对冲(动态) 对冲(固定比率)


累计收益率 36.07% 72.15% 34.58% 23.38%

最大回撤 13.49% 26.45% 20.00% 14.83%

可以看到,对冲后的最大回撤彰显其稳定性,而动态比率下的对冲也显示其动态调整对收益率的相对提升效果。

3.5 结论

由上述实验结果可见,两种对冲策略虽然在细节上有所差异,但均对策略的稳定性拥有提升效果。在追求收益率的同时,大幅降低了投资的风险性所在。总体上讲,我对自己本次编写的策略还是比较满意的。

0x04 附加思考

等同学们毕业工作之后,有了自己的积蓄,想买车买房钱又不够的时候,就会提出正确的问题:买股票好还是买基金好,怎么挑选好基金?

我认为,有一定量空闲资金且每天有足够的空余时间的,或有志于专业理财行业的同志,适合主动型理财。在这样的前提下,通过积极策略买入股票比较合适。但对小白、嫌麻烦但追求收益,或是时间不够的同志来说,买基金进行被动理财是个不错的选择。那么如何挑选好基金呢?我认为可以广于了解各个基金经理的历史业绩、观察他的持仓习惯是否有一定的战术战略,是否符合我们个人的偏好等,然后对比挑选基金。如果趋于看好行业,则买ETF基金较好;若相信经理的实力并偏好超额收益,则可去挑选一些主动型的基金。

0x05 总结

通过本次选股策略的代码编写以及论文叙述,我觉得自己对量化投资的方法方式有了一定的了解,在该过程中,查询到的诸多资料也让我获益匪浅。可以说,这一门通识课绝不仅仅是通识的定位所在,它让我对金融量化等概念有了更深入的了解与自己的思考。在今后的人生中,我应该也会将投资这一爱好进行下去,更加理智地看待金融市场。

参考文献

[1] 云金杞.谈一谈量化投资从哪里获取数据,https://zhuanlan.zhihu.com/p/219931158.2020.12.21.

[2] QData-本地量化数据说明书,https://www.joinquant.com/help/api/help?name=JQData.2020.12.23.

[3] 韩天一.股指期货在阿尔法策略中的应用,https://wlkc.ouc.edu.cn/bbcswebdav/pid-409342-dt-content-rid-5120815_1/xid-5120815. 2020.12.20.

[4] 雷璇.基于回归法和打分法的因子选股模型对比分析[D].大连理工大学,2019.

[5] 陈小米.【研究】如何用python实现Markowitz投资组合优化,https://zhuanlan.zhihu.com/p/20604930. 2020.12.24.

[6] 夏豪杰.金融期货交易策略,https://wlkc.ouc.edu.cn/bbcswebdav/pid-392996-dt-content-rid-4663883_1/xid-4663883_1.2020.12.20.

[7] 大象咖啡,一步步分离Alpha与对冲比率计算,https://www.joinquant.com/view/community/detail/b5ee73cdd19f074e25f7e112e76caf2a.2020.12.27.

[8] 贾稳. 基于动量效应的量化对冲策略设计及分析[D].上海师范大学,2017.