跳转至




2024

圣杯依然闪耀

圣杯依然闪耀 RSI 永远是我最爱的指标 -- 因为潮汐和回归是这个蓝色星球的生命年轮,这样的轮回也存在于交易世界。而 RSI 就是刻画市场中的潮汐和回归的最好指标之一。

年初我介绍过 Connor's RSI。这次我们将探索 Connors 提出的一个基于短时 RSI 的均值回归策略,重点是介绍策略优化应该从哪些方面入手。

策略实验及评测数据来自于Quantitativo 网。


策略概要

所有人应该都已经熟悉 RSI 指标了。我们常用的 RSI 指标是基于 6,12 和 24 周期计算出来的。

\[ RS = \frac{\text{SMMA}(U,n)}{\text{SMMA}(D,n)} \]
\[ RSI = 100\cdot\frac{\text{SMMA}(U,n)}{\text{SMMA}(U,n) + \text{SMMA}(D,n)} = 100 - { 100 \over {1 + RS} } \]

但是 Larry Connors 认为,2 周期的 RSI 可以更好的反映市场趋势,很可能是技术指标中的圣杯。他把这个观点发表在 2008 年出版的《华尔街的顶级交易员》一书中。在此后的 Connor's RSI 指标中,streak 的 RSI 正是使用 2 周期来计算的。

基于这样的 RSI,Connors 给出了以下均值回归策略:

  1. 标普 500 指数超过 200 日均线;
  2. 标普 500 指数的 2 周期 RSI 低于 5;
  3. 信号发出时,按收盘价买入;
  4. 当标普 500 高于 5 日均线时卖出。

用交易员的话来讲,这是一个在牛市(指数大于 200 日均线)短线回调(RSI 低于 5)时的买入策略。


因子检验

首先 quantitativo 进行了单因子检验。检验方法是对对所有 2 天 RSI 收于 5 以下的标的进行买入并持有 5 天,再计算收益。

这个统计包含了超过 21000 个标的,超过 250 万次事件(标普 500 收于 200 天均线之上)。测试中的亮点:

  1. 当任何给定股票的 2 天 RSI 低于 5 并在牛市中持有 5 天时,买入其平均回报率为 3.3%;
  2. 其中 60% 的事件获得正回报,每笔交易的预期回报为 9.8%;
  3. 40%的交易是负面的,每笔交易的预期回报率为-6.6%;
  4. 分布呈正偏。

quantitativo 还统计了反过来的情形,即如果我们在每只标的的 2 天 RSI 收于 5 以上时买入每只股票,并在牛市中持有 5 天的数据。我们将得到:

  1. 当任何给定股票的 2 天 RSI 高于 5 时,买入其预期回报率为 0.3%;
  2. 交易转为正值的可能性为 52%,预期回报率为 5.5%;
  3. 交易转为负值的可能性为 48%,预期回报率为 -5.1%。

quantitativo 还对两次测试是否属于同一分布进行了假设检验,结果 p 值远低于 0.05,证明两个分布显著不同。因此,第一次测试中的因子是存在 Alpha 的。

策略回测

接下来quantitativo进行了策略回测。这里策略设计如下:

  1. 使用SPY作为测试标的。
  2. 当以下条件满足时,在下一次开盘时买入SPY:
  3. 标普指数的RSI(2)收于5之下
  4. SPY高于200日均线
  5. 退出条件
  6. 当SPY收盘价高于前一天高点,则在下一次开盘时退出。
  7. 如果SPY收盘价低于200日均线

可以看出,回测策略与Connor提出的策略略有不同。为什么要进行这样的差异化?


这里的差异化,其实就是回测与实盘的差异。Connor给出的策略更理想化,而quantitativo的验证策略则更加接近实盘。这是我们做策略时一定要考虑的。

首先,尽管我们可以用标普500来回测,但在实盘中,更切合实际的方法是购买对应的ETF。这里的SPY就是以标普500为标的的ETF。

第二,Connor的策略是以收盘价买入。如果你的回测系统不够精确的话,最好是以次日开盘价买入。当然,如果你的回测系统和行情数据精确到分钟级,那么在国内,也可以利用集合竞价前一分钟的收盘价计算信号,再以集合竞价买入。

退出条件的差异,可以看成是quantitativo对原策略的一个优化。不过,我并没有看出来这个优化的意义。它的背后似乎并不存在任何交易上的原理支撑。看起来,这更像是quantitativo通过数据做出的过拟合。

Question

quantitativo在本次实验中,使用了长达25年的数据进行测试。如果经过这么长的时间回测,数据表现仍然很好,是否就可以说不存在过拟合?我很想知道你们怎么看。

那么,quantitativo的实验结果又是如何呢?


在SPY上的测试简直就是灾难。在整个回测期(25 年)中,使用 SPY 交易此策略提供了 67% 的回报。主要原因是交易次数太少,仅执行了 157 笔交易。

接着quantitativo改用了纳斯达克100指数ETF(QQQ)和三倍杠杆纳斯达克100ETF(TQQQ)。结果表明,在TQQQ上表现不错:

夏普比率分别达到了2.3(QQQ)和1.92(TQQQ),对指数标的而言,是相当不错的指标(特别是与A股对比)。


改进策略:增加因子

在前一次实验的基础上,quantitativo增加了资产组合。

他们把资金分成十份(10 slots),用于购买前一天RSI收于5以下的标的;如果universe中有10支以上的标的触发了入场信号,将按市值进行排序,优先考虑市值较小的股票。退出条件改为收盘价低于标的200日均线。

此外,他们还限制只交易流动性较好的标的: 1. 只交易过去3个月内完全没有停牌的标的 2. 如果标的过去3个月日均成交量中位数不足资金份额的20倍,则不纳入


Tip

实际上,在这里quantitativo已经引入了另一个因子,小市值因子,只不过它的权重比较低--是在RSI触发之后才应用权重因子。

这次的结果很不错,整体年回报率达到17.8%,是基准的3倍。但也存在问题,即所有这些都是在前8-9年实现的。该策略在 2008 年后停止执行,并从那时起输给基准。

原因何在?通过分析25年回测期间进行的11,380笔交易,quantitativo发现了很多退市。这种幼稚方法的问题在于,该策略优先考虑小盘股(在通过流动性过滤器后),它们退市的概率为 +70%。

第二次改进:降低退市风险

quantitativo再次改进了策略,这次的改进是将universe限制在只交易大型和超大盘股,这些股票的退市概率较低(分别为35%和9%)。

这一次效果非常明显。策略的年化回报达到了23.9%,是同期基准的4倍,夏普达到1.23%,最大回撤为32%,几乎只有标普的一半。

但是,之前就存在的一个问题,交易次数过于频繁仍然存在。现在一年仍然会交易461次。


第三次改进:减少slots

之前的实验使用了10个slots,这可能是导致交易次数过多的主要原因。于是,quantitativo将同时持有的标的数减少到2支。

现在,交易笔数由461次/年下降到90笔/年。并且实现30.3%的年回报率,是基准的5倍。

这里抛一个问题,年化上升,夏普会跟着上升吗?多给自己一点思考时间,会比全盘接受别人的观点更好。因此,我不在这里公布答案,你可以在留言问我答案,也可以在quantitativo网站上寻找这个答案。


结论

这篇文章介绍了一个基于短时RSI的均值回归策略,并在最后,给出了年化达30.3%的一个实现(未考虑滑点和交易手续费)。

这个策略的内核是短时RSI,尽管这个指标发明以来已经超过45年,但回测结果表明,只要你研究一件事足够深入,就很可能取得成功。

Quote

It's not that I'm so smart; it's just that I stay with problems longer. -- Albert Einstein

这个方案已经值回你的阅读时间,但更为重要的是,我们讨论了策略发现的一般流程和优化角度。我们再梳理一次,作为本篇的结束语:

  1. RSI代表着潮汐和回归,其背后是人性,因此它永远不会过时。
  2. 多因子策略也可以以某个因子为主,在交易过程中,以限制条件的方式引入其它因子。
  3. 文中给出了判断标的流动性强弱的方法,你也可以将其作为一个因子。
  4. 研发策略的步骤往往从单因子检验开始,再编写简单回测,然后根据回测结果一步步优化。
  5. 在优化过程中,quantitativo先是使用ETF,然后改用了10个slots,最终回到2个slots的方案。

[0721] QuanTide Weekly

本周要闻回顾

  • 上交所放大招,将发布上证全收益指数!
  • 私募巨头发声,大跌不是我们干的!
  • 交易所加强异常交易监管...

本周 Po 文

  • 基于 XGBoost 的组合策略...
  • 不能求二阶导的 Metrics,不是好的 objective
  • 全球大蓝屏!作为量化人,我的检讨来了
  • 不要去写书 除非是要与你的灵魂对话
  • 问薪无愧!自学量化大纲有这 75 页就够了

本周要闻回顾

  • 上交所放大招,将发布上证全收益指数!为便利投资者观察上海证券市场整体收益情况,上海证券交易所与中证指数有限公司决定自 7 月 29 日起正式发布上证综合全收益指数实时行情,同时将指数代码和简称分别调整为“000888”和“上证收益”。

  • 私募巨头发声,大跌不是我们干的!本周DMA 持股市值大降 2000 亿元,幻方、衍复相继发声,认为量化投资具有长期优势,不应被视为导致市场低迷的主要原因。2023年以来,DMA策略收益颇为优秀,成为私募的主要盈利策略,也因此遭到市场诟病。


  • 交易所持续加强异常交易监管,深交所本周共对 54 起证券异常交易行为采取了自律监管措施,上交所本周对个别波动幅度较大的可转债进行重点监控,对 49 起拉抬打压、虚假申报等证券异常交易行为采取了书面警示等监管措施。 上期所发布《上海期货交易所异常交易行为管理办法(修订版)》将于今年10 月 25 日实施。

  • 比特币盘中突破 67000 美元

  • 半年猛增 50%,中短债基金总体规模已超 8000 亿元。汇金二季度继续增持 ETF,申购金额或者接近 3000 亿元。股票型 ETF 规模年内增长超 4200 亿元,宽基 ETF 成为增长主力。

  • 受Trump和微软蓝屏事件双重打击,特斯拉周五盘中一度大跌近5%,最终收跌4.02%。

下周重要日历

  • 周一,央行将公布 7 月 LPR 报价。市场预期三季度末或四季度可能迎来降准或降息的新窗口,以进一步支持经济稳步增长

  • 周一起,融券保证金比例上调至 100%,私募证券投资基金参与融券的保证金比例由不得低于 100%上调至 120%。值得注意的是,在证监会宣布上述消息后,A 股市场融券规模已开始连续下滑。Wind 数据显示,截至 7 月 18 日,融券余额已减少至约 295 亿元,创出最近 4 年新低。

  • 7 月 24 日起发行超长期特别国债,本期国债为30年期固定利率附息债,竞争性招标面值总额550亿元

  • 本周将有三支新股发行,分别是力聚热能、博实结、龙图光罩。

  • 本周五将迎来成品油调价窗口,按测算,对应的国内汽柴油零售价应下调50元/吨。
信息来源:证券日报等,通过Tushare.pro接口综合汇编。

本周Po文

这周我们共发表5篇文章。《基于 XGBoost 的组合策略...》等两篇详细讲解了机器学习构建组合策略的框架和常见问题。


文章要点与结论:

  1. 通过两阶段式方案实现多因子、多资产的组合策略构建。第一阶段基于XGBoost构建多个多因子单标的模型,第二阶段通过经典的均值方差方案进行组合优化。
  2. 应该基于分类而不是回归来构建机器学习模型。基于时序的价格预测几乎没有意义(价格序列不具有平稳性)。
  3. 分类模型是以多因子为特征,以未来一周期的涨跌幅度digitize化作为标签来训练构建的。
  4. 对XGBoost模型而言,基本上无须考虑因子标准化。因子标准化甚至有可能引入副作用;但另一方面,因子标准化也有利于正则惩罚项。
  5. 损失函数与度量函数的差别在于,损失函数要能计算梯度。MAPE函数的不可导性决定了它不适合作为损失函数。
  6. 在金融领域,相对误差比RMSE更有意义,因此我们介绍了SMAPE -- 这是一个可作为损失函数的函数。

这两篇文章我们也集结后,发在本文末尾。

在这一期的量化工具专栏中,我们发表了获得NASA奖章的男人,带来了这些IPython技巧。IPython是非常轻量的交互式编程工具,尽管它的所有功能都可以在Notebook中找到,但它更轻,但仍然长袖擅舞,颇有飞燕之姿。

不要去写书 除非是要与你的灵魂交流中,我们披露了《Python高效编程实践指南》出版过程中的一些冏事。这本书会对量化人构建稳健的交易系统非常有帮助。


话音刚落,周五就发生了Windows蓝屏事件,正是因为CrowedStrike缺乏完善的CI/CD,才导致这一事件发生。而CI/CD正是本书详细介绍的内容之一。

问薪无愧,最全威的量化自学路线图中,我们介绍了Algos.org编写的这份量化自学大纲。

我们也将在8月底前,推出自己的量化自学路线图。除了更好的本地化之外(英文版中,一些工具、网站和数据源对国内市场不支持),我们还将更清晰地理出从入门到精通、从小白到不同的岗位的学习路径。

在大纲没有出来之前,大家可以暂时参照这份路线图:

75%


基于XGBoost构建多因子策略

如何在投资组合策略中运用上机器学习方法? 最近,我们翻了下之前存过的论文,决定对《A portfolio Strategy Based on XGBoost Regression and Monte Carlo Method》这篇论文进行解读。

这是论文抽象出来的一个基本框架图。

50%

这个框架能解决的什么问题呢?我们知道,在一个投资组合策略中,要重点考虑的第一个问题是,如何从给定的 universe 中,选择一部分股票纳入策略股票池;其次要考虑,这部分股票的持仓如何分配,使之在这个组合上,达到风险收益比最高。


后一部分,最经典的方法就是运用 MPT 理论,寻找有效投资前沿。这里既可以用凸优化求解,也可以使用蒙特卡洛方案。这一部分,我们之前有一个系列文章:投资组合理论与实战,从基本概念到实战细节,都讲得非常清楚,这里就不详述了。

如何从 universe 中选择股票进入股票池? 这在单因子模型中比较容易解决,就是选择因子分层中,表现最佳的那个分层 (tier) 的股票进入股票池。各标的的权重可以按因子载荷来分配,也可以使用 MPT 方法。

但如何在多因子模型中选择股票进入股票池?这一直是一个难题。我们常常提到的 Barra 模型也只是一个风控模型,并不能选择出最佳的股票池出来。


论文的思路是,将股票的纳入选择看成一个回归问题,即,通过多因子的训练,找出最能被模型预测的那些股票进入股票池

作者给出的结果是,在 2021、2020 和 2019 年,龙头股票投资组合的回报率分别为 27.86%, 6.20%和 23.26%。不过,作者并没有给出基准比较,此外,也没有深入分析,如果这些结果有超额收益的话,这些超额是来自于 MPT 呢,还是来自于 XGBoost。

这也是我们要对这篇论文进行解读的地方。希望通过我们的解读,你也可以学习到,究竟应该如何分析他人的论文,从中汲取正确的部分。

错误的回归

论文中使用的是 XGBoost 回归模型。这可能是值得商榷的地方。在资产定价模型中,我们要预测的是股票在截面上的强弱,而不是在时序上的走势

论文作者这里使用的方法是训练一个回归模型,从而使得它能较好地预测次日(或者后面一段时间的走势)。

R50

右图是论文作者得到的结果之一。看起来模型能比较完美地预测次日走势。


显然,由于 XGBoost 回归模型本身没有预测股票强弱的能力,所以,即使通过回归模型找出了完美拟合的股票,也没有任何意义。因为一支下跌中的股票,也可能被完美地拟合出来。所以,论文中提到的收益,即使有超额,很可能也来自于 MPT 理论。

但是,作者仍然给出了一个如何通过 XGBoost 来寻找多因子模型中表现最佳个股的线索。我们只需要把它改造成一个分类模型,然后通过分类模型,筛选出表现最好的股票就可以了

L50

训练集中的 X 部分不用改变,但我们需要重新设定标签,即 y 部分。对给定的因子\(X_i\),对应的\(y_i\)需要能反映是上涨或者下跌。如果有可能,我们可以将标签设置为 5 类,-2 表示大跌,2 表示大涨,中间部分以此类推。

然后构造分类器进行训练。训练完成后,通过模型预测出来属于大涨标签的,我们就放入股票池,此时可以平均分配权重,也可以通过 MPT 理论来进行优化。

端到端训练及新的网络架构

论文作者使用的框架是两阶段式的,即先选择股票进入策略池,再通过 MPT 优化权重。


但即使是在第一阶段,它仍然是两段式的。每次进行训练时,它都只使用了一个标的的多因子数据。因此,如果 universe 中有 1000 支标的,就要训练出 1000 个模型(这是论文中暗示的方法,也可以考虑一个模型,训练 1000 次)。

这么做的原因是技术限制。XGBoost 只支持二维输入。如果我们要使用多个标的的多个因子同时进行训练,就必须使用 panel 格式的数据,或者将多个标的的多个因子进行一维展开。但如果标的数过多,展开后的训练会很困难。

也就是,由于技术限制,要么进行单因子的多标的同时训练,要么进行多因子的单标的训练。

但是,论文作者在这里给出了一个方法,就是你可以分别训练多个标的各自的模型,然后同样分别进行预测,然后再通过 MAPE 进行评估。当我们改成分类模型之后,可以简单地看分类结果,也可以结合分类的 metric 评估(在时序维度上的),选择准确性和分类结果都好的标的,纳入策略股票池。

损失函数与度量函数

接下来,我们要分析 MAPE 这个函数在论文中的使用。以此为契机,适当深入一点机器学习的原理,讲以下两个知识点:

1. 损失函数和度量函数
2. XGBoost模型,因子数据是否要标准化

损失函数与度量函数

在机器学习中,有两类重要的函数,一类是目标函数(objective function),又称损失函数(loss function);一类是度量函数(metrics)

75%

损失函数用于模型训练。在训练过程中,通过梯度下降等方法,使得损失函数的值不断减小,直到无法继续下降为止,模型就训练完成。

训练完成之后的模型,将在test数据集上进行测试,并将预测的结果与真实值进行对比。为了将这个对比过程数值化,我们就引入了度量函数(metrics)

在sklearn中,提供了大量的损失函数和度量函数。下图列举了部分Sklearn提供的损失函数和度量函数:


可以看出,度量函数的个数远多于损失函数,这是为什么呢?

在论文中,论文作者并没有披露他通过xgboost训练的具体过程,只是说直接使用了xgboost的database,这个表述有点奇怪,我们可以理解为在参数上使用了XGBoost的默认值好了。


但是他重点提到了使用MAPE,从过程来看,是在把MAPE当成度量函数进行事后评估。

在XGBoost中,如果没有特别指定目标函数,那么默认会使用带正则惩罚的RMSE(rooted mean square error)函数。RMSE也可以作为度量函数,在论文中,作者没有使用RMSE作为度量函数,而是选择了MAPE(mean absolute percentage error),原因何在?如果MAPE在这个场景下比RMSE更好,又为何不在训练中使用MAPE?

看上去无论目标函数也好,度量函数也好,都要使得预测值与真实值越接近越好。既然都有这个特性,为什么还需要区分这两类函数呢?

要回答这些问题,就要了解XGBoost的训练原理,核心是:它是如何求梯度下降的。

XGBoost:二阶泰勒展开

XGBoost是一种提升(Boosting)算法,它通过多个弱学习器叠加,构成一个强学习器。每次迭代时,新的树会修正现有模型的残差,即预测值与真实值之间的差异。这个差异的大小,就由目标函数来计算。

在XGBoost中,多个弱学习器的叠加采用了加法模型,


即最终的预测是所有弱学习器输出的加权和。这种模型允许我们使用泰勒展开来近似损失函数,从而进行高效的优化。

XGBoost对目标函数的优化是通过泰勒二阶展开,再求二阶导来实现的。使用二阶导数,XGBoost可以实现更快速的收敛,因为它不仅考虑了梯度的方向,还考虑了损失函数的形状。

\[ f(x) \approx f(a) + f'(a)(x-a) + \frac{f''(a)}{2!}(x-a)^2 \]

正是由于XGBoost内部优化原理,决定了我们选择目标函数时,目标函数必须是二阶可导的。

RMSE是二阶可导的,但MAPE不是:MAPE从定义上来看,它的取值可以为零,在这些零值点附近连一阶导都不存在,就更不用说二阶导了。下图是MAPE的公式:

$$

\text{MAPE} = 100\frac{1}{n}\sum_{i=1}^{n}\left|\frac{\text{实际值} - \text{预测值}}{\text{实际值}} \right| $$

当预测值与实际值一致时,MAPE的值就会取零。

如何选择目标函数?

选择MAPE作为度量函数,不仅仅是便于在不同的模型之间进行比较,在金融领域它还有特殊的重要性:


我们更在乎预测值与真实值之间的相对误差,而不是绝对误差。在交易中,百分比才是王者。正因为这个原因,如果在训练时,能够使用MAPE作为目标函数,这样预测出来的准确度,要比我们通过RSME训练出来的准确度,更接近实际应用。

这就是在具体领域,我们改进算法的一个切入点。已经有人发明了被称为SMAPE的损失函数,它的公式是:

$$

\text{SMAPE} = \frac{100}{n} \sum_{t=1}^n \frac{\left|F_t-A_t\right|}{(|A_t|+|F_t|)/2} $$

到目前为止,sklearn还没有提供这个函数,但我们可以自己实现,并通过sklearn的make_scorer方法接入到sklearn系统中:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sklearn.metrics import make_scorer

def smape(y_true, y_pred):
    return np.mean(2.0 * np.abs(y_pred - y_true) / 
           (np.abs(y_true) + np.abs(y_pred)))

smape_scorer = make_scorer(smape, greater_is_better=False)

# 使用举例:在GridSearchCV中使用
grid_search = GridSearchCV(estimator=model, 
                           param_grid=params, 
                           scoring=smape_scorer)

Question: 既然训练中不能使用MAPE,那么论文在测试中,又为何要使用MAPE呢?

答案其实很简单,是为了便于在多个模型之间进行比较。在论文作者的算法中,每支股票都必须有自己的模型。由于每支股票的绝对价格不一样,因此,它们的RSME是不一样的,而MAPE相当于一个归一化的指标,从而可以在不同的模型之间进行比较,最终选择出误差最小的模型对应的股票,纳入策略股池。

但我们前面也提到过,论文作者的这个模型没有意义,改用分类模型会好一些。如果改用分类模型的话,损失函数也不再是RSME了,度量函数也不能是MAPE了。


标准化

论文中还提到,在训练之前,他将因子数据进行了标准化。

实际上,这也是没有意义的一步。因为XGBoost是决策树模型,它是通过特征值的比较来进行分裂和划分数据的,显然,分裂点的比较,并不依赖数据的量纲,因此,标准化就没有意义,反而可能带来精度损失问题,得不偿失。

Hint

如果因子数据使用单精度浮点数储存,那么如果两个小数只在小数点的第7位数字之后才产生差异,这两个数字在比较时,实际上是一样的。如果我们在进行标准化时,把两个原来有大小差异的数字,缩放到了只在第7位数字之后才出现差异,就产生了精度损失。

当然,事情也不能一概而论。XGBoost使用正则化来控制树的复杂度,包括对叶节点的权重进行L2正则化。如果你在训练XGBoost模型时,损失函数加了正则惩罚,而特征未经过标准化,正则化的效果可能会变差。

另外,论文中的方法是,每支股票一个模型,但如果只用一个模型,但拿1000支股票的数据来训练1000次呢?显然,这个时候,就必须要提前进行标准化了。


否则,收敛会很困难(当然,即使使用了标准化,也不保证就能收敛。能否收敛,要看众多股票是否真的具有同样的特征到标签的映射关系)。这并不是XGBoost的要求,而是根据我们使用XGBoost的方法带来的额外要求。

结论

对多数量化人来说,我们不可能像陈天奇那样自己撸一个机器学习框架出来,因此,要用同样的模型,做出更优的结果,就只能在数据标注、目标函数、评估函数和参数调优等方面下功夫了。这往往既需要有较深的领域知识,也要对具体的模型原理有一定的了解。

版权所有: 量化风云/QuanTide 公众号

全球Windows机器蓝屏,作为量化人,我的检讨来了

昨天下午,微软给大家放了个假。Windows又双叒死机了。不过,这一次不是几台机器,而是全球大范围宕机。这一刻,大家都是“正蓝旗”。

现在根本原因已经找到,绝大多数人的机器都已修复。根本原因在于,一家名为CrowdStrike的安全公司在例行更新时,部署了错误的配置文件到Windows上。

这个错误也是由于另一个比较少见的错误引起的。CrowdStrike软件使用了微软部署在美国中部的云服务Azure,但刚好这个数据中心出现了异常。

这个异常就导致了CrowdStrike在获取配置时,导入了错误的配置信息。这些错误信息下发后,软件终端基于错误的配置运行,就会在Windows终端额外加一个名为csagent.sys的驱动,而这个驱动存在bug,会导致系统陷入蓝屏死循环。

这个错误导致航司、银行和交易所受到重大影响,后面是否会面临巨额赔偿,还不清楚,但微软股价已受严重冲击。

目前还不清楚国内有多少从事交易的机构和个人受影响,但是,这也给我们量化人提了一个醒,你构建的交易系统,它安全可靠吗?我们应该如何构建自己的量化交易系统,使得它即使遇到类似的问题,也能保持稳定运行?

这里提几条建议。

第一,一定要达成高覆盖的单元测试和CI/CD流程。一定要意识到任何软件、硬件系统都是有bug的。在你构建量化交易系统时,一定要达成高覆盖单元测试和CI/CD流程。

单元测试不仅仅是在我们开发阶段帮助我们确保各个模块的功能正确,更重要的是,它设置了一组基准,可以帮助我们确定在时刻发生变化的环境下,系统的各项功能仍然满足基准运行要求。

正如这次CrowdStrike案例所显示的那样,即使你的交易系统并没有升级(就像这次的Windows),但交易系统依赖的第三方组件(比如数据源,Pandas或者Numpy等)仍然可能升级。我们的交易系统在接受任何升级前,都要确保升级后的系统,仍然完全能通过我们所有的测试用例。

像CrowedStrike这样的软件,其实他们平常的测试也是很严格的,但为什么还会出现这样的故障?这里固然有比较偶然的原因(这次是Azure的故障引起),但是,很可能CrowedStrike的测试没有经过CI/CD的覆盖。只有实现了CD,这样才能保证连部署也被测试覆盖到,才会尽量减少错误。

传统上,量化团队都是金融专业的人领导的,他们可能缺乏软件工程的经验,不太懂测试、CI/CD这些专业知识,正因为这样,我写完《Python高效编程实践》这本书之后,特地请了两位金融界的大咖来推荐。因为自己做量化金融有好多年了,知道这个领域,非常需要系统化的软件工程方法来确保软件质量。

第二,关闭一切自动更新。生产环境下一切自动更新都是非常危险的,必须关闭。只有经过严格测试的更新,才能应用。

第三,更新系统时一定要使用灰度部署。

在部署上,CrowedStrike这次也犯了一大错误,就是没有实现灰度部署。实际上,安全软件权限很高,一旦出错,往往就会引起很严重的故障。因此,灰度部署就格外重要。

如果CrowedStrike实现了灰度部署,比如,一开始只部署1%的机器,并且监控升级后的情况(收集数据是灰度发布的一部分),然后在没有错误报告的情况下,再逐步扩大推送范围,就完全可以避免出现这么重大的事故。

灰度发布同样适用于量化系统。2012年8月1日,骑士资本在纳斯达克交易所部署了一个新的交易软件,但是由于没有充分测试,该软件在激活时触发了一系列错误的交易指令,导致公司在45分钟内损失了约4.4亿美元。最终导致了它被Jefferies Group收购。

骑士资本案例报告

事后分析,如果正确地实施了灰度发布,完全可以避免这样的错误。

如果有杠精:这件事比较复杂。一言以蔽之,不是没有实施灰度发布,而是没有正确地实施灰度发布。

据说做期货的,往往是90%的时候都在赚钱,但就是不到1%的极端情况,让你跳了楼。

第三,构建可控的系统。

如果你的交易信号系统构建在AI模型之上,那么,风控模型就一定不要构建在黑盒子之上,一定要设置熔断机制,到点无条件地止损(当然这会引起其它家的量化也跟进止损,但换个角度,如果你跑得太晚,那么被埋的就是你自己)。

第四,再先进的系统,也不能无人值守。即使有了全自动的量化系统,也不要把手工交易员都裁了。如果你去看三峡大坝的发电厂,你会发现,发电是高度自动化的,但电脑显示屏前的值守人员,仍然会严格倒班。

问薪无愧!
自学量化大纲有这75页就够了

题图为 MIT 的 Simmons University。版权声明 wiki/public domain。

该建筑属于 MIT 的下属学院 Simmons University,由裁缝 John Simmons 捐建。Simmons Hall 被认为是 Boston 最美的一座建筑。Simmons University 对女性友好,该校的 MBA 课程是全球第一个专门为女性设计的 MBA 课程。到目前为止,其本科教育还是以女生为主,研究生阶段则是男女混合。

这是 Stat Arb 给自学量化的人开的一份清单。他的博客有 9000 多名付费用户。清单是 pdf 格式,74 页,内容非常全面。

【下载链接】

Stat Arb这个名字来自 Statistical Arbitrage(统计套利),真实身份其实正在摸鱼的业内人士。不过这不重要,关键看他给的资源好不好。

我拿到的这个清单是 2024~2025 版,刚刚发布半个月。之前他每年都有发布这样一个清单,并且一直在根据情况变化,及时修订。内容非常全面,不同职业规划目标的读者,都能从中受益。

我个人最喜欢的是它的数据资源部分。相当一部分资源是免费的,尤其是 crypto 项目和 kaggle 上的数据集,大约几十个G。它也提供了一部分付费数据转储的,但可能访问时需要密码,这些密码在❌(🐦)上可以找到。

求职者可能更喜欢它的第17章内容,这部分是关于职业规划、面试准备的。我们也在陆续介绍大学和投资机构的情况,以备你将来可能需要投递这些学校或者机构。

章节内容

chap01

介绍了机器学习和算法交易相关的教科书,包括基础教材和进阶教材,如《Quantitative Trading 2nd edition》《Algorithmic Trading》《Machine Trading》等,并对一些模型和方法进行了评价。

chap02

衍生品和波动率交易方面的教科书,推荐了一些关于衍生品和波动率交易的教科书,如《Hull Options Futures and other Derivatives》《Option Trading & Volatility Trading》等,并介绍了一些相关的知识和资源,如动态对冲、随机波动率等。

chap03

YouTube 视频资源,推荐了一些 YouTube 视频,包括 Ben Felix、Patrick Boyle、Leonardo Valencia 等博主的视频,涵盖了波动率、算法交易、信号处理等多个主题。 课程:介绍了 Coursera 上 Robert Shiller 的《Financial Markets》课程,以及 Andrew Ng 的机器学习和深度学习课程。还提到了一些与量化交易相关的课程和项目,如 RobotJames、HangukQuant 和 Euan Sinclair 的课程。

chap04

推荐了一些播客资源,如 Tick Talk、Flirting with models、Mutiny fund 等,认为播客是非常重要的学习资源,能提供很多实用信息。

chap05

交易平台和经纪公司:介绍了股票和其他资产类别的交易平台和经纪公司,如 IBKR、TD Ameritrade 等,以及数字资产领域的交易平台和经纪公司,如 Binance、Okx、Bybit 等。

chap06

神经网络/机器学习/炒作:认为神经网络在量化交易中不是核心领域,不建议深入研究,推荐学习回归、非参数方法、树、GAMs 等。

chap07

关键数学概念:强调了数学在算法交易中的重要性,推荐了一些学习数学的资源,如 Measure Theory、Econometrics、Stochastic Calculus、Probability Theory 等。

chap08

优化(确定性和随机):介绍了优化在量化交易中的应用,如估计隐含波动率、分布、自动化阿尔法发现、投资组合优化等。

chap09

高频交易和做市:推荐了一些关于高频交易和做市的教科书和资源,如《High - Frequency Trading: A practical guide to algorithmic strategies and trading systems 2nd edition》《Inside The Black Box》等。

chap10

其他波动率/衍生品资源:推荐了一些关于波动率和衍生品的资源,如 https://moontowerquant.com/select - content - from - the - quant - and - vol - community、Options Starter Pack 等。

chap11

编码语言评论和资源:推荐使用 Python 进行量化交易研究,若想进行高频交易或做市,则需要学习 C/C++(在加密领域,Rust 更受欢迎)。

chap12

项目:介绍了一些与深度学习相关的项目,但提醒读者要避免过度复杂化,应专注于回归和实用的方法。

chap13

数据:介绍了数据的来源,包括付费数据的转储、交易所的免费数据和竞赛数据等,并推荐了一些数据提供商。

chap14

GitHub 存储库:推荐了一些与算法交易相关的 GitHub 存储库,如 https://github.com/stefan - jansen/machine - learning - for - trading、https://github.com/barter - rs/barter - rs 等。

chap15

轻松阅读:推荐了一些与金融行业相关的书籍,如《Liars Poker》《Flash Boys》《Irrational Exuberance》等。

chap16

职业:介绍了量化交易的通常职业路径,包括就读顶尖大学、参加实习、学习面试问题等,并推荐了一些资源。

chap17

套利指南:主要聚焦于数字资产领域的套利,介绍了不同类型的套利,如资金套利、三角套利、现货套利等,并提供了一些扫描套利机会的网站和资源。

chap18

做市指南:介绍了做市的要点,包括边缘(准确预测中间价格和低延迟反应事件的能力)、价差(根据资产体积调整价差)和风险(避免复杂的库存平衡方程,因为模型中的相关性不一定成立)。

chap19

配对交易指南:介绍了一些关于配对交易的资源,如@systematicls 的文章、作者博客上的相关文章、Github 上的配对交易策略等。

chap20

季节性指南:提供了作者博客上关于季节性策略的概述链接,以及与 HangukQuant 共同撰写的关于季节性策略的论文和 PNL 曲线。

chap21

动量指南:提供了作者博客上关于动量策略的资源链接。

chap22

博客阅读:推荐了一些与量化交易相关的博客,如 The Quant Stack、The Quant Playbook、HangukQuant 等。

chap23

Twitter 账号关注:列出了一些值得关注的 Twitter 账号,如 Vertox_DF、Ninjaquant_、BeatzxBT 等。

chap24

如何学习这些材料:强调了学习方法的重要性,建议读者筛选相关内容、实施和讨论所学知识、避免构建不必要的工具或虚荣项目,以及注重从实践中学习。

chap25

其他路线图:推荐了一些其他的量化交易资源列表,如 Vertox 的资源列表、Moontower 的资源列表(尤其是期权方面)、Moontower 的博客和在线作家、Options Starter Pack、QM 的教科书、QuantGuide 等。

不能求二阶导的metrics
不是好的objective

   

Quote

最消耗你的东西,不是别人,而是自己的念头。人生之苦,苦在执着。人生之难,难在放下。强大不是对抗,而是接受。一念放下,万般自由。

To accept the things I cannot change, the courage to change the things I can, and the wisdom to know the difference

接上一篇。

今天我们要分析 MAPE 这个函数在论文中的使用。以此为契机,适当深入一点机器学习的原理,讲以下两个知识点:

1. 损失函数和度量函数
2. XGBoost模型,因子数据是否要标准化

损失函数与度量函数

在机器学习中,有两类重要的函数,一类是目标函数(objective function),又称损失函数(loss function);一类是度量函数(metrics)

75%

损失函数用于模型训练。在训练过程中,通过梯度下降等方法,使得损失函数的值不断减小,直到无法继续下降为止,模型就训练完成。

训练完成之后的模型,将在test数据集上进行测试,并将预测的结果与真实值进行对比。为了将这个对比过程数值化,我们就引入了度量函数(metrics)

在sklearn中,提供了大量的损失函数和度量函数。下图列举了部分Sklearn提供的损失函数和度量函数:

可以看出,度量函数的个数远多于损失函数,这是为什么呢?

在论文中,论文作者并没有披露他通过xgboost训练的具体过程,只是说直接使用了xgboost的database,这个表述有点奇怪,我们可以理解为在参数上使用了XGBoost的默认值好了。但是他重点提到了使用MAPE,从过程来看,是在把MAPE当成度量函数进行事后评估。

在XGBoost中,如果没有特别指定目标函数,那么默认会使用带正则惩罚的RMSE(rooted mean square error)函数。RMSE也可以作为度量函数,在论文中,作者没有使用RMSE作为度量函数,而是选择了MAPE(mean absolute percentage error),原因何在?如果MAPE在这个场景下比RMSE更好,又为何不在训练中使用MAPE?

看上去无论目标函数也好,度量函数也好,都要使得预测值与真实值越接近越好。既然都有这个特性,为什么还需要区分这两类函数呢?

要回答这些问题,就要了解XGBoost的训练原理,核心是:它是如何求梯度下降的。

XGBoost:二阶泰勒展开

XGBoost是一种提升(Boosting)算法,它通过多个弱学习器叠加,构成一个强学习器。每次迭代时,新的树会修正现有模型的残差,即预测值与真实值之间的差异。这个差异的大小,就由目标函数来计算。

在XGBoost中,多个弱学习器的叠加采用了加法模型,即最终的预测是所有弱学习器输出的加权和。这种模型允许我们使用泰勒展开来近似损失函数,从而进行高效的优化。

XGBoost对目标函数的优化是通过泰勒二阶展开,再求二阶导来实现的。使用二阶导数,XGBoost可以实现更快速的收敛,因为它不仅考虑了梯度的方向,还考虑了损失函数的形状。

\[ f(x) \approx f(a) + f'(a)(x-a) + \frac{f''(a)}{2!}(x-a)^2 \]

正是由于XGBoost内部优化原理,决定了我们选择目标函数时,目标函数必须是二阶可导的。

RMSE是二阶可导的,但MAPE不是:MAPE从定义上来看,它的取值可以为零,在这些零值点附近连一阶导都不存在,就更不用说二阶导了。下图是MAPE的公式:

$$

\text{MAPE} = 100\frac{1}{n}\sum_{i=1}^{n}\left|\frac{\text{实际值} - \text{预测值}}{\text{实际值}} \right| $$

当预测值与实际值一致时,MAPE的值就会取零。

如何选择目标函数?

选择MAPE作为度量函数,不仅仅是便于在不同的模型之间进行比较,在金融领域它还有特殊的重要性:

我们更在乎预测值与真实值之间的相对误差,而不是绝对误差。在交易中,百分比才是王者。正因为这个原因,如果在训练时,能够使用MAPE作为目标函数,这样预测出来的准确度,要比我们通过RSME训练出来的准确度,更接近实际应用。

这就是在具体领域,我们改进算法的一个切入点。已经有人发明了被称为SMAPE的损失函数,它的公式是:

$$

\text{SMAPE} = \frac{100}{n} \sum_{t=1}^n \frac{\left|F_t-A_t\right|}{(|A_t|+|F_t|)/2} $$

到目前为止,sklearn还没有提供这个函数,但我们可以自己实现,并通过sklearn的make_scorer方法接入到sklearn系统中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sklearn.metrics import make_scorer

def smape(y_true, y_pred):
    return np.mean(2.0 * np.abs(y_pred - y_true) / 
           (np.abs(y_true) + np.abs(y_pred)))

smape_scorer = make_scorer(smape, greater_is_better=False)

# 使用举例:在GridSearchCV中使用
grid_search = GridSearchCV(estimator=model, 
                           param_grid=params, 
                           scoring=smape_scorer)

Question: 既然训练中不能使用MAPE,那么论文在测试中,又为何要使用MAPE呢?

答案其实很简单,是为了便于在多个模型之间进行比较。在论文作者的算法中,每支股票都必须有自己的模型。由于每支股票的绝对价格不一样,因此,它们的RSME是不一样的,而MAPE相当于一个归一化的指标,从而可以在不同的模型之间进行比较,最终选择出误差最小的模型对应的股票,纳入策略股池。

但我们前面也提到过,论文作者的这个模型没有意义,改用分类模型会好一些。如果改用分类模型的话,损失函数也不再是RSME了,度量函数也不能是MAPE了。

标准化

论文中还提到,在训练之前,他将因子数据进行了标准化。

实际上,这也是没有意义的一步。因为XGBoost是决策树模型,它是通过特征值的比较来进行分裂和划分数据的,显然,分裂点的比较,并不依赖数据的量纲,因此,标准化就没有意义,反而可能带来精度损失问题,得不偿失。

Hint

如果因子数据使用单精度浮点数储存,那么如果两个小数只在小数点的第7位数字之后才产生差异,这两个数字在比较时,实际上是一样的。如果我们在进行标准化时,把两个原来有大小差异的数字,缩放到了只在第7位数字之后才出现差异,就产生了精度损失。

当然,事情也不能一概而论。XGBoost使用正则化来控制树的复杂度,包括对叶节点的权重进行L2正则化。如果你在训练XGBoost模型时,损失函数加了正则惩罚,而特征未经过标准化,正则化的效果可能会变差。

另外,论文中的方法是,每支股票一个模型,但如果只用一个模型,但拿1000支股票的数据来训练1000次呢?显然,这个时候,就必须要提前进行标准化了。否则,收敛会很困难(当然,即使使用了标准化,也不保证就能收敛。能否收敛,要看众多股票是否真的具有同样的特征到标签的映射关系)。这并不是XGBoost的要求,而是根据我们使用XGBoost的方法带来的额外要求。

结论

L33

对多数量化人来说,我们不可能像陈天奇那样自己撸一个机器学习框架出来,因此,要用同样的模型,做出更优的结果,就只能在数据标注、目标函数、评估函数和参数调优等方面下功夫了。这往往既需要有较深的领域知识,也要对具体的模型原理有一定的了解。

最后,博主的新书《Python高效编程实践指南》(机工出版)已经上架。作为量化人,要提升自己的工程水平,这本书是不二之选。自荐一下。

你可能不知道的8个IPython技巧

题图为科罗拉多大学博尔德分校的麦基礼堂。博尔德分校是科罗拉多大学系统的旗舰大学,共有5名诺奖学者,1名图灵奖。

IPython的作者Fernando Pérez在此攻读了粒子物理学博士学位。2001年,他将IPython作为业余项目开发,后来成为Jupyter项目的联合创始人。由于对Ipython和Jupyter的贡献,他先后获得NASA杰出公共服务奖章、ACM软件系统奖。他还是Python 软件基金会的会员,这是决定Python发展方向的组织。

让你的光芒闪耀! 来自科罗拉多大学的校训。


IPython 是一个强大的交互式 Python shell,它比标准的 Python shell 提供了更多的功能和便利。

IPython 由 Fernando Pérez 在 2001 年创建,旨在为科研人员和数据科学家提供一个更高效、更易用的交互式 Python 编程环境。随着时间的发展,IPython 已经成为科学计算、数据分析和机器学习领域中不可或缺的工具之一。

IPython的成功,也催生了Jupyter。2014年,Jupyter 从 IPython 项目中分离出来,并扩展到其它语言。Jupyter这个名字,正是来源于 Julia、Python 和 R 这三种语言的首字母组合。

50%

尽管有了Jupyter Notebook,但在今天,我们仍然有很多理由使用ipython,核心原因就是,它比Jupyter更轻量 -- 无论是从安装角度还是使用角度。更轻,但仍然长袖擅舞,颇有飞燕之姿。

安装ipython比安装Jupyter更快更容易。

1
pip install ipython

然后在命令行下输入ipython就可以使用了。

1. 使用%magic命令

与Notebooke一样,我们在IPython中也可以使用魔法命令。比如 %timeit np.arange(1_000_000)。如果要对整个代码块执行魔法命令,需要使用两个%

2. 使用Tab自动补全

输入pd.后按 Tab 键,就可列出 pandas 模块的所有属性和方法。再按一次Tab键,就会导航到具体API上,再回车就能输入啦!

小宠*书用户看不到这里的动画,抱歉


3. 交互式帮助

这个跟Jupyter中一样,在对象后输入一个?,就可以显示帮助文档,输入两个??,就可以显示源代码。显示源码的功能简直太好用了。

4. 持久化临时变量

使用 %store 命令将变量持久化到磁盘,即使重启内核也不会丢失数据。

比如:

1
2
%store variable_name 存储变量。
%store -r variable_name 从磁盘恢复变量。

5. 绘图

对很少使用IPython的人来说,很可能没有想到,即使IPython运行在shell下,但也是可以绘图的。


1
2
3
import matplotlib.pyplot as plt 
plt.plot([1,2,3], [1,2,3])
plt.show(block=True)

这样会弹出一个窗口,显示正在绘制的图形。记住,最后一行的参数block=True是关键。否则你将什么也看不到。

6. 历史命令及关联命令

这一组命令是真正double工作效率的关键。

可以通过%hist输出所有的历史命令。可以通过_i(n)来检索前n个命令。

比如,在我的试验中,

1
_i10

输出了import matplotlib.pyplot as plt

一个关联的用法是,将历史命令存到一个文件中。这是通过%save来实现的。

1
%save example 4 5 6 8

然后你可以重置工作区间(%resset)重新加载example.py文件(%load)

这样就可以逐步编写和验证的方式,不断构建和改进代码,最终生成高质量的可用python文件。

7. 启用调试

一旦代码运行出错,你就可以输入%debug进入调试模式。这点比Jupyter要方便。在调试模式下,你可以通过p命令来检查变量值,这往往是出错的原因。

比如,下面的代码在运行时会出错:

1
2
3
4
5
6
def example_function():
    # 尝试使用未定义的变量 `data`
    i = 10
    print(data)

example_function()

出错后,立即输入%debug,然后就可以用l命令来列出代码,p命令来检查变量值,q命令来退出。下图演示了如何进入调试状态,列代码及查看变量的过程:


8. 使用bookmark

如果我们经常使用ipython,甚至同时开发了好几个项目,那么bookmark功能将非常有用。下面的例子演示了如何创建书签,并使用它。


1
%bookmark my_project ~/Projects/my-python-project

这将创建一个名为my_project的书签,指向~/Projects/my-python-project目录。下次我们打开ipython窗口,就可以通过这个书签,直接进入my-python-project目录:

1
2
3
# 如果忘记了创建的书签,可以用%bookmark -l来列出所有书签
# 如果要删除书签,可以用%bookmark -d来删除
%cd -b my_project
## 往期相关笔记

我们也发过两期关于Jupyter使用技巧的笔记,验证过了,确实80%的人没用过!

量化人如何用好Jupyter环境?(一) 量化人如何用好 Jupyter?(二)

基于 XGBoost 的组合策略基本框架

Quote

人的放纵是本能,自律才是修行。短时间让你快乐的东西,一定能够让你感到痛苦。反之,那些让你痛苦的东西,最终一定会让你功成名就。记住,低级的快乐,放纵即可拥有,高级的快乐,只有克制才能获得。 -- 罗素

放正文之前,先打个假,这段话不是罗素说的,是啰嗦说的。一些箴言必须借助名人之口才能传播,可见折服我们的不是真理,而是附着在权威身上的权势和名利。

这次将解读一篇博士论文,思路“新奇”,但不要见论文就拜。


如何在投资组合策略中运用上机器学习方法? 最近,我们翻了下之前存过的论文,决定对《A portfolio Strategy Based on XGBoost Regression and Monte Carlo Method》这篇论文 1 进行解读,共分三部分:

Readmore

  • 基于 XGBoost 的组合策略基本框架
  • 关于目标函数的讨论
  • 关于因子的选择

本文是第一部分,论文构建的基于 XGBoost 的基本框架。

基本框架

50%


这是论文抽象出来的一个基本框架图。

这个框架能解决的什么问题呢?我们知道,在一个投资组合策略中,要重点考虑的第一个问题是,如何从给定的 universe 中,选择一部分股票纳入策略股票池;其次要考虑,这部分股票的持仓如何分配,使之在这个组合上,达到风险收益比最高。

后一部分,最经典的方法就是运用 MPT 理论,寻找有效投资前沿。这里既可以用凸优化求解,也可以使用蒙特卡洛方案。这一部分,我们之前有一个系列文章:投资组合理论与实战,从基本概念到实战细节,都讲得非常清楚,这里就不详述了。


如何从 universe 中选择股票进入股票池? 这在单因子模型中比较容易解决,就是选择因子分层中,表现最佳的那个分层 (tier) 的股票进入股票池。各标的的权重可以按因子载荷来分配,也可以使用 MPT 方法。

但如何在多因子模型中选择股票进入股票池?这一直是一个难题。我们常常提到的 Barra 模型也只是一个风控模型,并不能选择出最佳的股票池出来。

论文的思路是,将股票的纳入选择看成一个回归问题,即,通过多因子的训练,找出最能被模型预测的那些股票进入股票池

作者给出的结果是,在 2021、2020 和 2019 年,龙头股票投资组合的回报率分别为 27.86%, 6.20%和 23.26%。不过,作者并没有给出基准比较,此外,也没有深入分析,如果这些结果有超额收益的话,这些超额是来自于 MPT 呢,还是来自于 XGBoost。

这也是我们要对这篇论文进行解读的地方。希望通过我们的解读,你也可以学习到,究竟应该如何分析他人的论文,从中汲取正确的部分。

错误的回归

论文中使用的是 XGBoost 回归模型。这可能是值得商榷的地方。在资产定价模型中,我们要预测的是股票在截面上的强弱,而不是在时序上的走势


论文作者这里使用的方法是训练一个回归模型,从而使得它能较好地预测次日(或者后面一段时间的走势)。下图是论文作者得到的结果之一:

看起来模型能比较完美地预测次日走势。

Warning

即使看起来完美地预测了次日走势,这里也有一个较大的误区,新手切记:这种预测是典型的胜率大、赔率小,总体收益不确定。


显然,由于 XGBoost 回归模型本身没有预测股票强弱的能力,所以,即使通过回归模型找出了完美拟合的股票,也没有任何意义。因为一支下跌中的股票,也可能被完美地拟合出来。所以,论文中提到的收益,即使有超额,很可能也来自于 MPT 理论。

但是,作者仍然给出了一个如何通过 XGBoost 来寻找多因子模型中表现最佳个股的线索。我们只需要把它改造成一个分类模型,然后通过分类模型,筛选出表现最好的股票就可以了

L50

训练集中的 X 部分不用改变,但我们需要重新设定标签,即 y 部分。对给定的因子\(X_i\),对应的\(y_i\)需要能反映是上涨或者下跌。如果有可能,我们可以将标签设置为 5 类,-2 表示大跌,2 表示大涨,中间部分以此类推。

然后构造分类器进行训练。训练完成后,通过模型预测出来属于大涨标签的,我们就放入股票池,此时可以平均分配权重,也可以通过 MPT 理论来进行优化。

当然,我们构造标签和训练数据集时,要综合考虑实盘的持仓周期。


端到端训练及新的网络架构

论文作者使用的框架是两阶段式的,即先选择股票进入策略池,再通过 MPT 优化权重。

但即使是在第一阶段,它仍然是两段式的。每次进行训练时,它都只使用了一个标的的多因子数据。因此,如果 universe 中有 1000 支标的,就要训练出 1000 个模型(这是论文中暗示的方法,也可以考虑一个模型,训练 1000 次)。

这么做的原因是技术限制。XGBoost 只支持二维输入。如果我们要使用多个标的的多个因子同时进行训练,就必须使用 panel 格式的数据,或者将多个标的的多个因子进行一维展开。但如果标的数过多,展开后的训练会很困难。

也就是,由于技术限制,要么进行单因子的多标的同时训练,要么进行多因子的单标的训练。

但是,论文作者在这里给出了一个方法,就是你可以分别训练多个标的各自的模型,然后同样分别进行预测,然后再通过 MAPE 进行评估。当我们改成分类模型之后,可以简单地看分类结果,也可以结合分类的 metric 评估(在时序维度上的),选择准确性和分类结果都好的标的,纳入策略股票池。

这是我们从论文中应该学习到的方法。


Hint

这里有可能构造联合训练模型吗?根据我查到的资料,XGBoost 是不支持联合训练,或者多任务学习的。这也给我们学习人工智能的同学指出了一个研究方向。在量化领域,端到端的算法模型还有较大的探索空间。

结论

本期解读介绍了基于 XGBoost 的多因子组合策略的模型构建方法。它是一个两段式构造,通过训练单标的、多因子的多个模型,实现多因子模型选股。但是,论文作者错误地选择了回归模型,因而论文的结果很可能无法到达预期。

下一期文章,我们聊聊 MAPE 这个 metric。

50%

Pandas高级技巧-1

在量化领域,Pandas是不可或缺的工具,它以强大的数据处理和分析功能,极大地简化了数据操作流程。

今天我们介绍两个技巧,都跟因子检验场景相关。第一个技巧是日期按月对齐;第二个是如何提取分组的前n条记录。讲解的概念涉及到group操作、索引的frequency概念以及多级索引的操作(读取和删除)。

在最后一个例子中,更是反复使用了groupby,以简洁的语法,完成了一个略为复杂的数据操作。


日期按月对齐

我们在做因子检验的时候,如果使用的是日线以上的频率,依赖于所使用的数据源,就有可能遇到这样一种情况:比如,今年的1月份收盘日是1月31日,但个股可能在1月31日停牌,那么数据源传给我们的月线,就可能把日期标注在1月30日。也就是,我们在生成月度因子数据时,有的个股的日期是1月31日,有的则是1月30或者更早的时间。

如果我们使用Alphalens来进行因子检验,就会产生日期无法对齐,计算前向收益出错的问题。不过,这不是我们今天要介绍的问题。我们今天只讲解决方案,即如何实现所有个股的因子日期都对齐到月。

假设我们有以下数据:


这里无论是1月还是2月,两个个股的收盘日期都不一致。最简单的方案是使用index.to_period函数,将日期对齐到月份。

1
df.index = df.index.to_period(freq='M')

经过转换,就会生成下面的结果:

这样的转换尽管实现了对齐,但会丢失具体的日期信息。我们也可以使用groupby来实现同样的功能:

1
2
3
4
(df
    .groupby(['asset', pd.Grouper(freq='M')])
    .last()
    .reset_index("asset")

结果是:

50%

语法要点是,asset与index构成一个事实上的惟一索引,我们现在要调整索引的日期,按'asset'进行分组,并且通过Grouper来指定分组的频率。Grouper是作用在索引上的。

.last()提供了如何从分组记录中选取记录的功能。它是一种聚合函数,除此之外,还有first, min, max, mean等。在我们的例子中,由于asset与index构成一个惟一的索引,所以,无论使用first, last还是min, max,结果都一样。

提取分组的前n条记录

假如,我们通过因子检验,已经确认了某个因子有效,想使用test数据集来进行验证。test数据集也由好多期数据组成,我们需要对每一期数据,取前20%的股票,然后计算它在之后的T1~Tn期的收益,以决定这个因子是否能投入使用。

这实际上是一个DataFrame分组,再取头部n条记录的问题。


假设数据是:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
df = pd.DataFrame(
    [
        (datetime.datetime(2024, 1, 31), "000001", 9.86),
        (datetime.datetime(2024, 1, 31), "000002", 10.2),
        (datetime.datetime(2024, 1, 31), "000003", 9.84),
        (datetime.datetime(2024, 1, 31), "000004", 11.2),
        (datetime.datetime(2024, 2, 29), "000001", 10.2),
        (datetime.datetime(2024, 2, 29), "000002", 11.2),
        (datetime.datetime(2024, 2, 29), "000003", 9.83),
        (datetime.datetime(2024, 2, 29), "000004", 11),
    ],
    columns=["date", "asset", "factor"]
)

我们要取每个月factor最大的前n个,并且生成一个dict,key为每月日期,values为对应的asset数组。

1
2
3
4
5
6
7
8
9
top_n_assets = (df
      .groupby(level=0)
      .apply(lambda x: x.nlargest(2, 'factor')['asset'])
      .reset_index(level = 1, drop = True)
      .groupby(level=0)
      .apply(list)
     ).todict()

top_n_assets

输出结果是:

1
2
3
4
date
2024-01-31    [000004, 000002]
2024-02-29    [000002, 000004]
Name: asset, dtype: object

这里的技巧是,当我们要按索引进行分组时,我们要使用grouby(level=?)的语法。Pandas支持多级索引,第一级索引一般使用level=0来引用,第二级索引使用level=1来引用。

在使用groupby之后,生成的DataFrame就有了两级索引,这个中间结果显示如下:

1
2
3
4
5
6
date        date      
2024-01-31  2024-01-31    000004
            2024-01-31    000002
2024-02-29  2024-02-29    000002
            2024-02-29    000004
Name: asset, dtype: object

我们通过第4行的reset_index来删除掉第二级索引。注意在Pandas中,删除索引也是通过调用reset_index来实现的。到此为止,我们实际上已经实现了提取分组的前n条记录的任务。


第5~6行是将提取结果扁平化,即将按多行排列的asset,压缩成一个list,结果仍然是一个DataFrame,但每个日期只有一行,其值包含了当期前n个asset。

今天介绍的两个小技巧,都是因子检验中常常遇到的。熟悉掌握Pandas技巧,就能快速搞定因子检验,加快我们因子研发的迭代速度,你学会了吗?

2024已过一半,千禧年发布了这道脑筯急转弯

今天为大家带来一道千禧年基金的脑筋急转弯题目。

千禧年是一家全球领先的对冲基金管理公司,由以色列裔美国金融家Israel Englander于1989年创立。到今年6月止,管理规模是677亿美元,在职人数5500多人。截止2022年,该公司管理产品的净收益在1989年之后成立的对冲基金中,排名第四。

千禧年内部管理上是一种赛马机制,现在大约由330个投资团队组成。在这里,不限制个人投资风格,一切以业绩为准,有一定的竞争压力。


公司为投资团队提供强大的平台。目前,该公司管理了来自400个供应商的2000多个数据集,共10万亿条数据记录,超过2000TB的压缩存储数据。

这道题目是这样的:


简单翻译一下,就是数字N由3^2024个3组成。要求找出这样一个数字,它是3的幂中,能整除N的最大的一个。如果我们缩小问题的规模的话,333, 333333333都是合适的N的取值,但3333,33333等则不是,而9, 27则是对应的满足条件的最佳答案。

千禧年一般都是在出题的同时就公布答案,所以,题目的娱乐性就更强一些,这一点不像简街。简街出题后并不会立即公布答案,如果你把答案提交给简街,还可能登上leader board。所以,简街的题目,有一定的挑选人才的味道在里面。

这道题千禧年给出的答案是3^2025。你答出来了吗?


这道题其实也就是中学奥赛难度。仅仅是给出答案并不困难,但它考察的是答题者的逻辑推理能力、数学基础和解决问题的创造性思维。

尽管千禧年的brain teaser与人才筛选没有关联,但有空多解解千禧年的brain teaser也是大有益处的。为什么?

L50

如果你要求职一家公司,就最好把这家公司研究透。如果你是面试销售,最好知道他们家有什么产品、有哪些客户、竞争对手是谁;如果你是面试技术,最好知道他们在用什么技术栈、深入到了什么程度。最次,你也要知道除了薪资之外,自己会不会喜欢这家公司

如果你连他们网站上的brain teaser都不愿意了解,又如何能说自己喜爱这家公司呢?

说到职业发展,我们再回到千禧年的赛马机制。这种赛马机制给员工带来机会的同时,也带来一定的压力,因此,千禧年员工有一定的流动性,特别是做策略的同学,不一定能长期留下来。

但是,千禧年的从业经历就犹如黄金阶梯一样,对此后的职业发展,颇有助益。


在国外,世坤(world quant)的许多人来自于千禧年(部分因为2018年千禧年与它们成立了合资公司)。

在国内,目前最优秀的私募基金,核心人物多有千禧年的从业经历,比如九坤的王琛、姚齐聪,诚奇资产的何文奇、张万成;明泷投资的裘慧明和灵均投资的马志宇等。

最后再问一遍,这个题你答出来了吗?如果你熟悉Python 3.8关于数字表示的新语法,即可以使用333_333来表示数字333333,会不会很容易猜出答案并悟出原理?

333

333_333_333

333_333_333_333_333_333_333_333_333

ORB! Alpha 达到年化 36%

这个策略来自 Carlo Zarattini 等人,在 Quantpedia 2023 年大赛中获第三名。他们研究了最近 6 年的美股市场,发现聚焦在热门股 (Stocks in Play) 中时,5 分钟 ORB 策略实现了超过 1600%的总净收益,夏普高达 2.81,年化 Alpha 为 36%。同期标普只有 198%。

这个策略简单暴力,只利用了量比、ATR 和 5 分钟突破等非常简单的技巧。数年以前,有个朋友通过机器学习,得到过一个两周翻倍的策略,我一直没好意思问他实现细节。但通过他的调仓记录来看,最终实现的效果与此庶几近之。


ORB 策略最早由 Toby Crabel 于 1990 年提出,他在《Day trading with short term price patterns and opening range breakout》一书中,详细地介绍了这个策略及系统实现。此后,无论是产业界还是学界都在持续探索和改进这个策略。

2023 年,Carlo Zarattini 等人在 ORB 的基础上,加入了 stocks in play 的限制,将策略的夏普提升到 2.81,年化 Alpha 则达到惊人的 36%(扣除交易费用,参考巴菲特的 20%左右,大奖章的 39%左右)。

选股过滤器

Zarattini 等人提出的策略有以下过滤器:

  1. 开盘价要超过$5。
  2. 过去 14 天平均成交量超过 1 百万股
  3. 14 天 ATR 要超过$0.5
  4. 量比至少为 2,并且
  5. 只交易量比为前 20 的个股

交易执行

根据开盘前 5 分钟的方向,确定当日交易方向。比如,如果开盘头 5 分钟为阳线,则考虑在该股上做多;反之做空。如果头 5 分钟为阳线,即使后面是向下突破,也不考虑做空。


在上图中(注意红色为阴线、空心为阳线),个股以阴线开盘,因此当天的交易方向确定为做空。10 点,股价向下突破(超过头 5 分钟最低价),开空仓,并在 10% ATR 处下止损单。当日尾盘卖出。

下图则是另外两个例子,分别显示了在做多和做空情况下,何时开仓。左图的例子特别提示了,并不是每一次开仓都能获利,仍然有风险因素要考虑。


75%

关于这个策略,如果你还在期待我讲更多,很遗憾。我讲完了。

大道至简

请原谅我用了一句割韭菜的老师们常用的一句话。不过,毕竟咱们是做量化的,高低也得整几句理论的。接下来,就是见证数学公式和金融理论的时刻。

Why it works?

Zarattin 策略成功的关键不是 ORB 策略本身,而是通过条件过滤器,筛选出来了一个独特的小宇宙 (universe)。这个小宇宙的居民,都是高能粒子,有足够的波动性。

另外,由于有美股 T+0 和做空的特性,可以实现斩断亏损,让利润奔跑(通过 ATR 及仓位控制,让每支股票即使亏损,对组合的冲击也控制在 1%以内)。


Tip

A 股没有 T0 和个股做空手段(不是所有的券都能融到),但并不意味着这个策略不能在 A 股应用。

我们逐一解释一下过滤器中的条件。

股价大于$5,不用多解释,可怜之人,亦必有可恨之处。低价股便宜总有便宜的理由。

过去 14 天平均成交量超过 1 百万股。这一条尽管有多种解释,但它在短线操作中的作用,就是要保证成交活跃,这样交易时才不会有太大的冲击成本。

14 天 ATR 超过 0.5,是要保证股性活跃。ATR 是一个绝对值,我们也可以用 20 天均线值转换成百分比,这样可以得到一个适合所有标的的 ATR 标准。

第 4 和第 5 条是选股器的战斗机! 量比是关键,是信号发射器,只此一手,选出热门股 (stock in play)。第 4 条主要是保证在整体市场清淡的情况下,还能保证选出的个股满足要求。

如果你是一些割韭菜号的读者,你很可能听他们这样讲早盘选股策略:

Quote

集合竞价时,把量比前 10 的个股加入自选,观察到 10:50,上涨且涨幅不超过 3%,下探时不破分时均线的,买!


如果这些策略没有一定的合理性,是不可能割到韭菜的。

Zarattin 等基于大量的数据统计,发现了量比与盈利能力(含多空双边)之间的统计相关性,证明了选股老司机的理论有合理性。见下图:

这里的量比就是大家理解的量比,为严谨起见,我们也把他们的计算公式也发布出来:

\[ RelativeVolume_{t,j} = \frac{ORVolume_{t,j}}{\frac{1}{14}\sum_{i=1}^{14}ORVolume_{t-i,j}} \]

这里\(ORVolume_{t,j}\)是个股 \(j\)\(t\) 日前 5 分钟的成交量,\(ORVolume_{t-i,j}\)则是个股\(j\)\(t-i\)日前 5 分钟的成交量。


从数据上看,只选择量比超过 30 倍的个股,看起来性价比更高。但根据 Zarattin,这样实际上会减少一年之中的交易机会,进而减少了总盈利。

除了基于统计数据之外,我更关心策略背后的经济和博弈原理。量比放大究竟意味着什么?如果搞清楚这一点,我们就能知道这一关键因子会不会失效,如果会,何时失效。

用好一个因子,比挖掘新的因子更重要。因为大道至简,趋动股票上涨的因素,说破天,也无非就是那么几种。

在有经验的短线交易者之间,一直流传着只做热门股的策略。一家公司可能因为这些信息的披露而成为热门股:

  1. 超预期的收益报告披露或者预披露。
  2. 专利、药品、许可的批准或者撤销。
  3. 重组和收购或者建立战略联盟、伙伴关系。
  4. 重要产品发布、拿下重要合同(或者在竞标中失去)或者客户。
  5. 管理层变动
  6. 股票拆分(本文作者:即送转)、回购、发债
  7. 突破关键技术点位。

除第 7 点之外,其背后都蕴含着公司盈利能力变动的信息。因此,一旦这些信息被公布,往往就会引来众人的关注,提醒他们去交易该股。无论这些信息是在盘中发布的、还是盘后发布的,人们在晚上都有充分的时间来接收、消化这些信息,并且为第二天早间的操作做出决策。


因此,如果某家公司在头一天有 breaking news 放出来,第二天的成交量就一定会比前一天大许多;反过来,如果一支股票的成交量突然放大,则往往也意味着该公司出现了超预期的消息。

如何预测这些消息对方向决定作用呢?分析师往往是屁股指挥脑袋,别听他们的。也别自己分析,因为股票这个事,你分析正确没用,只要其他人都分析错了,你分析正确也白搭。

ORB 策略告诉我们,看早盘 5 分钟的方向。如果是阳线,大概率是做多,如果是阴线,大概率是做空。

股市是赤裸裸的金钱民主。大家用钱来决定方向,非常真诚。

为什么要强调量比?因为如果做多时成交量没有明显放大,意味着交易的人仍然是场内资金,场内资金往往会做骗线。只有大量的场外资金涌入时,金钱博弈出来的方向才是真实的方向。

如果有人想改变这个方向,他就得拿出更多的钱来。他想高调,但实力他也不允许啊。这样确定的方向,像极了渣男的爱情,它可能短暂,但每一次都很真诚。

现在,你还要用大模型来进行文本挖掘,进行预测吗?还是开始相信,一切信号,都蕴藏在量价之中?

百闻不如一练。在大富翁量化环境中,我们提供了2005年以来的分钟级数据,回测支持到分钟,你可以亲自己试一下这个策略。


Tip

写给随机游走和 EMH 学说爱好者。这两个学说在股票市场上没有一席之地(但在期货和期权上是正确的)。

熬夜的人看不到早间新闻。市场主体接收、消化以及响应这些信息的时间绝不可能同步。

公司经营所得的利润总在源源不断地注入股市,股市总的来说正方向的(当然不包括缅甸)。

它前进的步伐在大时间跨度上,会大于 GDP 的增长速度,因为股市里聚集的应该是一国最好的公司。

在 A 股的应用

要做到文章所说的收益率和低风险,需要满足两个条件,一是要能 T0 止损。第二个则与市场无关:你需要有一套量化交易系统,能快速计算出全市场 5 分钟量比,能够快速下单,一键止损。原文虽然提到了做空,但仅做多也是 OK 的。

但在 A 股,我们无法做到 T0 止损,这会放大一些风险。如果可能,可以考虑转债品种。

原文(PDF)还研究了不同时间窗口(10, 15, 30 等)下的 ORB 策略,并且提供了加量比约束与不加量比约束的策略对比。需要原文的读者请转发本文后索取。