跳转至




Index

你可能不知道的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%


  1. PDF 

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 策略,并且提供了加量比约束与不加量比约束的策略对比。需要原文的读者请转发本文后索取。

高薪金领都用啥编程语言?SQL、Python领航,附排名!

最近两天,收到私信咨询,想进入量化领域难吗?

提问者没有介绍任何自己的背景,也没有明确说明具体要从事什么岗位。因此这是一个无法回答的问题。不过,我会持续跟进这个问题,并给出一些参考资料。

今日焦点:金融界最需要什么样的编程技能。数据来源于Revelio Labs和eFinacialCareers。前者是人力情报数据分析公司,后者是金融专业求职平台。


根据Revelio Labs 的数据,在金融服务业最受欢迎的编程语言前十排名如下:

你可能想不到,SQL在金融领域有着王者般的地位。在整个科技领域,SQL与岗位的相关性只占18%,但在金融招聘领域中,却有25%左右的岗位要求掌握SQL。

当然,也有许多人并不把SQL视为编程语言。老实说,SQL只能视为一种数据库查询语言,我们无法用它来完成数据查询之外的工作。

因此,Python才是真正意义上的王者,不仅仅是在金融领域,根据TIOBE 6月的排名,它仍然位居榜首,并且受欢迎程度在上升中。


但是,金融行业对C++和Rust这样的互联网热门编程语言的需求并不大,尽管这两种语言在高频交易中不可或缺,但毕竟高频交易比较小众、无法吸纳大资金,因此行业的重心不会在这里。

越是低频交易,越能吸纳大量资金。因此,像Python这样尽管性能不佳,但开发快速灵活的语言,在金融界被广泛使用。此外,SQL的大量使用,也证明了金融业对大数据处理能力的要求并不高,大量的数据处理场景仍然可以使用SQL来实现。这也是完全可以理解的,因为在中低频交易广泛使用的财务数据,数据量并不大。

Java位列三甲也是意料之中。大量的事务系统,包括公司网站仍然会使用Java来开发。


Javascript能上榜,很可能也是因为这样的用途。投资公司为了保持神秘和高科技形象,他们的网页也常常做的比较酷炫。比如Millennium(千禧年)的官网上,就常常使用Javascript炫技。在他们最新的主页上,展示了js制作的磁力线效果和各种reveal特效。

千禧官网

这界面丑是丑了点。但理工男的形象是立住了。所以,前端做得好,也是有机会进金融行业的。

R排在第4名也不意外。R语言在数据科学领域被广泛使用,R语言天然有很多统计方案的模块,它的语法简单,支持管道操作,对于临时性的数据分析处理非常友好。SAS上榜的原因也是一样。SAS与R对因子分析都天然支持得很好。统计模块及因子分析,都是金融行业数据分析的基础。


比较令人意外的是VBA。实际上VBA上榜,蕴含了在金融行业必须熟练掌握Excel的意味。所谓熟练掌握Excel,决不是仅仅是指掌握了它基于图形界面的功能,而是要求在关键时刻、复杂功能及快速处理大量数据时,能够使用VBA来编写脚本。

具有强大的编程能力,对于金融领域求职有多重要?我们看一下eFinancial Careers最近发布的一个全球信贷和可转换债券主管岗位,这是一个年薪$50万到$80万之间的工作:

Quote

A renowned investment firm is looking for an Head of global credit and convertible bonds to report to their CIO function ...

Experience

  • Fixed income in preferably a sell-side company
  • Front-office
  • Experience with arbitrage
  • Experience with credit, equities, convertibles, CDS
  • Strong programming skills (Python or R, SQL, Excel or VB)
  • Strong communication skills and ability to work in a team

如果你是一名在校生,可能多少掌握一点SQL和Python,但究竟要达到什么样的程度才算精通呢?

关于Python,在工程技巧方面可以参考我的新书《Python高效编程实战指南》(预定7月开售),算法方面可以多刷leetcode、kaggle的题,或者简街、千禧的puzzle专栏,我们的专栏也不时会有一些性能优化的技巧。

50%

关于SQL,如果是开发岗,需要了解数据分区规划、索引优化、SQL优化等,如果是数据分析岗,则只需要了解如何构建复杂的查询即可。这些查询主要是窗口函数应用、子查询与自连接、复杂条件筛选与分组等。

反抗者的崛起!Fawce 和 Quantopian 的量化之路

2008 年的金融危机后,华尔街开始围绕人工智能、算法策略和海量数据构建美丽新世界。掌握编程和算法的大拿是这个新世界的宠儿。也有一批反叛者,他们拒绝华尔街的征召:宁愿穿着睡衣在书房里工作,也不愿在豪华大楼的格子间正襟危坐。

Quantopian 正是这一群人的领袖。John Fawcett(昵称 Fawce)则是这家公司的头儿。

对量化萌新来说,John Fawcett 的名字略显生疏。这篇文章,我们将起底 John Fawcett,了解他从四大天坑专业成功转型量化金融的历程,并和他一起,追问量化事业的意义。

Fawcett 出生于一个普通的家庭。他的父母在退休之前,基本上都要同时打 3~4 份工来维持生计。尽管如此,他的父母坚持把子女的教育放在第一位,供他上了哈佛。他还有一个哥哥,后来选择了教育事业,成为了一名中学校长。这样的出身和家庭背景,对他的理念形成产生了重要的影响。

Fawcett 本科毕业于哈佛,专业是四大天坑之一的材料学。在千禧年前后的.com 泡沫白热化期间,他爱上了编程,于是搬到旧金山,为 Scient(一家软件咨询公司)工作。在这里,他管理美国职业棒球联盟的视频编码项目。

L50

John Fawcett 的量化之路起源于爱情的指引。他在 Scient 的事业很顺利,但他的女朋友在波士顿上医学院,于是,他又回到了东部,并在一家对冲基金找到了一份分析师的工作。Fawcett 发现这时的自己还并不擅长资产管理,他的工作是为投资经理编写软件,使得信息的收集和分析得以自动化。

很快,Fawcett 就离开了这家公司,并且创建了 Tamale Software。这家公司开发了用于基本面分析的软件。客户是对冲基金和资产管理公司。Fawcett 很快就取得了成功,2008 年,他把公司以 7000 万美元的对价,卖给了 Advent,这是一家位于旧金山的为投资者提供软件和服务的公司。Fawcett 继续为 Tamale 工作了一段时间,在这期间,Advent 强大的销售队伍,给 Tamale 带来了新的资源,比如新加坡主权基金、来自挪威和美国各地的基金经理成为他的客户。

在这段期间,他还接触了大量的在物理学、计算化学、信号处理领域的博士,对他们在市场方面独特的看法所吸引:即通过下钻到海量数据,建立模型来挖掘未发现的投资机会。

同时,他也了解到,即使这些人有很强的编程和算法能力,也对量化交易非常感兴趣,但由于之前没有投资经验,他们不得不被挡在传统的金融机构门外。

Fawcett 决心改变这种状态,给金融袪魅,实现量化投资过程的平民化,要为业余交易者--包括从来自康奈尔大学的计算机学生,到为互联网公司工作的高级数据科学家,再到机械工程师--为他们提供进入量化领域的机会,这是 Fawcett 曾经幸运地拥有、但不是所有人都能得到的机会。

要有光。

于是,他构建了 Quantopian。在 Quantopian,他们为社区提供海量数据和量化工具、甚至是昂贵的回测平台(指运行时所需的计算资源)。任何人都能免费加入这个社区,通过 Python 和 Notebook 构建自己的投资策略,并进行纸面上的投资。

一旦某人的策略在 6 个月的实时模拟交易中胜出,他就将获得一笔 10 万美元的基金管理权,正式开始实盘交易。如果继续成功,他将获得平台提供的高达 5000 万美元的支持。社区的另一职能则是为未来宽客提供教育资源。

Quantopian 的想法迅速吸引了大量的宽客:航空航天工程师、消费品公司的增长分析师、数据科学家、系统工程师、黑客、和博士生。在高峰时期,Quantopian 聚集了 12 万名会员,并且得到了像 Point 72 这样的投资巨头的认可,从他们那儿得到了 2.5 亿美金的资管规模。不仅如此,Quantopian 的商业模式不仅在美国、甚至在全球都被模仿,被福布斯评为美国最有前途的公司之一。

但是,也许是 Quantopian 的名字带着某种宿命式的悲剧色彩,也许是 Quantopian 的运营模式并不完美 -- 实时数据和回测引擎的运营费用真的得很贵,但Quantopian并不能从这些资源中得到多少回馈。尽管 Fawce 承诺要为所有人提供一个实现他们梦想的机会,但 Quantopian 自己最终却活在了梦想的光环之外。在运营 9 年之后,2020 年 11 月 14 日终止了运营。

Tip

Quantopian 的名字来源于 Quant 和 Utopia(乌托邦)。这表明,Fawce 在创建 Quantopian 之初,就带着某种改变量化交易的理想。但这个名字,也无疑一开始就暗含了某种悲剧色彩。

在 Quantopian 终止运营之后,许多用户猛然发现,自己在社区中留下了大量的 Notebook、想法、互动和回忆。

一位用户写道,“我一生中从未见过有这么多聪明人愿意与我分享如此多的信息而不求任何回报。我现在并将永远感激你们为我所做的一切”。

另一位用户则说,“在 2016 年加入后的几个月内,我学会了 Python,编写了所有基于 Excel 的策略,参加并赢得了第 22 场比赛,并且开始在 IB 进行实时交易。之前的我没有相关学位和任何经验,但现在我正在面试纽约的大项基金。Q 改变了我的生活。”

Quantopian 的失败,只是商业上的失败。在实现金融平民化的愿景上,Quantopian 已经取得了很大的成功。今天,Quantopian 开发并开源的量化工具,无论是 zipline, 还是 pyfolio 或者 Alphalens 等等,都已经成为某种事实上的标准。

如果没有这些软件,很难想像,一个业余的量化人、或者规模较小的机构该如何起步:传统的金融人并不太熟悉编程、而纯粹的计算机专业人士则不太理解金融理论。Quantopian 把因子检验、资产组合管理、回测等量化必备的方法,以接近开箱即用的方式,教给所有人。

Quantopian提供的教育资源和平台更是帮助了许多人成功转型。

L50

在Quantopian的网站上,Fawcett分享了赛义德·拉赫曼的转型故事。赛义德出生在一个股市受到污名化,股市经常与赌博联系在一起的国家。他在本科期间接受了时间序列分析和数据科学的训练,并通过互联网攻读了 CFA 1 级。进一步深造在他的国家是不可能的,但去美国学习是一个对他难以抉择的重大决定,更不用说由于缺乏奖学金带来的财务障碍(在美国读金融真是太贵了!)。幸运地是,在他读研究生期间,发现了 Quantopian。对于赛义德来说,这个平台不仅仅是一个工具,更是知识和机会的灯塔。正是在这里,赛义德不仅磨练了自己的技能,还找到了灵感和社区。

赛义德在一次分享中,具体地谈到了社区的经验贴与教科书的重大不同:

Quote

Max Margenot from your team once in his webinars went through OU (Ornstein–Uhlenbeck process - a stochastic differential equation that's used in understanding mean-reverting process), those were things that one normally finds in textbooks or expensive programs like CQF, but here Max was explaining it using Python, and as a student trying to wrap my head around the practical applications of these complex topics, the content your team released was just pure gold. 大意:奥恩斯坦-乌伦贝克随机过程在教科书和CQF这样昂贵的课程中,都只介绍了理论,但Max Margenot在webinar中分享了如何通过Python来实现这样复杂深奥的模型,这些内容弥足珍贵。

滋养了赛义德的,不仅仅来自Quantopian的教育资源。2017 年和 2018 年的 QuantCon 更是成为他的重要舞台,为他打开了社交、学习和曝光的大门。

在 2017 年的演讲上,他关于强化学习在量化方面的探索得到了许多人的关注,最终他于次年加入杰富瑞(Jefferies Group)的数据科学团队。

成功转型之后的赛义德也开源了自己的框架:MBATS 和 Cloud-MBATS,这两个框架专为在外汇现货和股票市场进行回测和实施基于机器学习的策略而设计。

这种分享行为植根于他自己的经历和 Qantopian 的影响,反映了赛义德对量化交易知识和工具平民化的信念,也成为金融平民化理念逐渐被人接受的一个例证。

这也正是 Fawce 的愿景。“我们的使命是打破量化圈的封闭,使得它能对所有人开放”。Fawce 在 Quantopian 网站上的一篇博客中这样写道,“众包阿尔法是一个登月计划,但 quantopian 成功地在宇宙中留下了痕迹,并让量化金融界的很大一部分了解我们并使用我们的工具”

Quantopian 和赛义德等人的工作,为下一代宽客,特别是那些来自贫困背景、可能无法轻松获得此类资源的宽客提供了支持。如果没有 Quantopian 发出的号召,这些人的生活不会有机会改变。

Quantopian 旅程的结束并不意味着 Fawce 对金融平民化探索的终止。在 Quantopian 终止运营后,Fawce 和 Quantopian 一起合并进入了 Robinhood。这是一家主要面向散户的股票和加密货币经纪公司,在网上提供完全免费的服务。Robinhood 更是旗帜鲜明在把“democratize finance for all”写入了公司愿景。

Tip

Robinhood 是中世纪英国民间传说中的侠盗,是一位劫富济贫、行侠仗义、亦正亦邪的绿林英雄。一般译作罗宾汉。Robinhood公司使用这样一个名字,别有深义。

Robinhood 到 2022 年 4 月止,拥有 2280 万个账户和 1590 万个活跃用户,是一个更大的社区。这不是结束,也许反而是涓涓细流汇聚成河,是另一个探索的开始。

加入 Robinhood 之后的 Fawce 很少高调活动。不过,Quantopian 的老用户惊喜地发现,在 2023 年底,借着感恩节的时机,Quantopian 重启了社区教育,对每位在校学生免费开放。只要你的大学在university-domain-list 当中,就可以免费注册并获得量化课程。

这也许是为了回应 Quantopian 关闭之后社区的呼声,以及他内心深处的价值观。在他的博客中,Fawce 写到,我哥哥的教育事业对我来说也是一种启发。我们的父母把我们的教育放在第一位。Quantopian 背后的大部分理念,即对机会和教育的奉献,来自我的父母和我的兄弟。将教育视为如此深刻的价值观也让我非常感激听到 Quantopian 为人民教育服务的故事。

结束语

在编写关于因子分析与机器策略的课程的过程中,无意中发现了 Fawce 的故事。受同样的理念激励的,不仅仅是 Quantopian, Fawce, Saeed,也包括分布在世界上其他地方的人,包括我自己。于是我决定暂停写作,花几天时间挖掘一下 Fawce 的故事,并和大家分享。

因为知道因何而战,永远比战斗本身更重要。

给所有量化人、和准备进入量化行业的人。

Barra风险模型构建完全指南

Barra风险模型是业内最有名的多因子模型之一。它最初由Barra Inc(创始人Barr Rosenberg)提出,后来被MSCI(明晟)收购,因此现在是MSCI的资产。在MSCI网站上,我们还可以看到名为BarraOne的产品推介。

很多想学习Barra模型的人,不知道Barra有一个官方的完全指南(《Barra Risk Model Handbook》),全文共204页,系统地阐述了如何构建Barra风险模型,是最权威的一本指南。

Barr Rosenberg大学主攻的是文学(UC Berkeley),后来才转攻经济学。Everbody can quant,只要你想。


关于Barra模型,常见的误解之一就是它是用来预测的投资模型。但实际上,它只是风险归因分析模型。关于这一点,最权威的说法无疑来自Barra自己的介绍:

Quote

Of course, MFMs have their limitations. They predict much, but not all, of portfolio risk. In addition, they predict risk, not return; investors must choose the investment strategies themselves.

手册先用10页左右的篇幅解释了什么是多因子模型,以及相关的数学基础。

Tip

关于因子分析的数学基础,可以参考Peter Tryfos(约克大学教授)的《商业分析与预测方法》中的第14章,讲得深入浅出。

在第二和第三部分,先是回顾了从马科维茨到CAPM以及APT,然后介绍了Barrar 权益多因子模型:

50%



下载

暴力美学!洗盘模式如何检测?

无洗盘,不拉升。 筹码收集阶段,股价呈现出上涨形态,也吸引到许多不坚定的跟风盘,它们将成为主升过程中的不利因素。

因此,在拉升之前,主力会采用洗盘的方式,将这些不坚定的低价筹码洗下车。这个过程中往往暴涨暴跌,犹如一匹烈马,要摆脱它身上的骑手一样。

暴力洗盘,某种程度上就成为了行情快速上涨之前的信号之一。

这篇文章,我们量化实现的技术问题:如何快速检测出洗盘模式?


定义

L50

暴力洗盘是在证券市场上观察到的一种经验模式,因此没有严格的定义。一般把两阳夹一阴、且涨跌幅都巨大的情况认为是暴力洗盘。在本文中我们把两阳夹两阴、且涨跌幅都较大的情况定义为暴力洗盘。但我们介绍的方法,也完全适用于其它模式,只需要微调参数即可。

如左图所示,标的在1号位置之前,经过一段时间的吸筹,由于期间股价上涨,已经吸引了一些跟风盘。主力在1号位置拉出20cm,在这一过程中,较多跟风筹码被锁定在涨停位置。

第2天起主力开始洗盘,连续两天,分别下跌14.4%和18.9%。此时在1号位置买入的筹码因为忍受不住巨大的跌幅,忍痛交出筹码。主力筹码增加,成本降低,为后面的拉升留出了空间。

第4天主力将个股拉涨9.4%,表明洗盘结束。

随后几天的整理,主要是留出时间,让下一波的跟风盘有时间发现这支标的,并且有信心跟随买入。紧接着使用一系列小阳线做出上升趋势,最终再拉出一个20cm,从第4天起,短期涨幅高达87%。


我们为什么要使用两阳夹两阴的4天模式来定义洗盘?

因为经过两天的洗盘,从时间和空间上看,洗盘效果会更好(考虑到交易者心理因素,一些人第一天亏损后,往往还不会绝望,第二天继续下跌,更容易崩溃卖出)。另外,从一些技术指标上来看,经过连续两天大幅下跌,技术指标修复比较到位,也更能为后面的拉升腾出上涨空间。

我们为涨跌幅设置一个阈值,如果期间的每个bar的涨跌幅超过这个阈值,我们就认为发生了洗盘。在我们的示例中,使用的阈值是0.05,即涨跌5%。

下面我们来看代码实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 示例1
def feature_washout(bars, threshold=0.05):
    """返回在bars中最后一次洗盘结束的位置,-1表示最后一个bar,
        0表示不存在洗盘模式
    """
    close = bars["close"]
    opn = bars["open"]
    truerange = np.maximum(np.abs(close[1:] - close[:-1]), 
                           np.abs(opn-close)[1:]) 
    # 百分比化
    tr = truerange / close[:-1]
    sign = (opn < close)[1:] * 2 - 1
    signed_tr = tr * sign

这里我们使用了truerange这个变量名,是因为这段代码脱胎于技术指标TR

这段代码解决如何将涨跌幅转换为由1,-1和0表示的模式,以便我们后面进行模式检索。

如果当天涨跌超过5%,或者实体的振幅超过5%,我们就将其标记为1或者-1,否则标记为0。标记的符号由它的形态是阴线还是阳线决定。阴线为-1,阳线为1.

我们通过这样一段简单的代码就实现了求阴阳线的功能:

1
(opn < close) * 2 -1

其结果将生成由1和-1组成的数组。无论是涨还是跌,我们总是认为,阴线是洗盘。所以,高开大阴线,即使收盘是上涨的,我们也当成洗盘来处理。

下图就是高开大阴线洗盘一例:

75%


在判断每个bar的涨跌幅、或者实体的振幅是否超过阈值时,我们使用了一个简单的技巧,即通过np.maximimum来从多个数组中,以 element-wise 的形式选取最大值。即,如果有数组\(A\)\(B\),那么\(np.maximum(A, B)\)将返回一个数组,其元素为\(A\)\(B\)对应位置的元素中的较大值。

也就是,如果结果是\(C\),那么\(C_0\)将是\(A_0\)\(B_0\)中的较大值,\(C_1\)将是\(A_1\)\(B_1\)中的较大值,以此类推。

除了使用\(np.maximimum\)这种 ufunc 之外,实际上\(np.max\)也可以用来完成这项任务,只是我们需要先将数组\(A\)\(B\)堆叠成一个矩阵:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 示例2
A = np.arange(4)
B = np.arange(3, 7)
C = np.arange(8, 4, -1)

Z = np.vstack((A,B,C))

# 通过np.max求每列最大值
r1 = np.max(Z, axis=0)

# 通过np.maximum求最大值
r2 = np.maximum.reduce([A, B, C])

# 比较两种方法的结果是否相同
np.array_equal(r1, r2)

为了提供更多信息,示例中我们演示了三个数组按元素求最大值的情况。答案是要使用reduce方法。如果只在两个数组间进行比较,则可以只使用np.maximum

经过示例1处理后,我们可能得到如下所示的数组:

[ ... 0.04 -0.02 -0.06 0.04 -0.04 -0. 0.2 -0.14 -0.19 0.09 -0.03 ...]

显然,我们还应该把它二值化,转换成为[大阳,大阴,大阴,大阳](即[1, -1, -1, 1])这样的模式:

1
2
3
4
5
6
7
8
9
# 示例3
encoded = np.select([signed_tr > threshold, 
                    signed_tr < -threshold], 
                    [1, -1], 0)

for i in range(len(encoded) - 3, 0, -1):
    if np.array_equal([-1, -1, 1], encoded[i:i+3]):
        return i - len(encoded) + 2
return 0

我们通过select方法完成了二值化转换。接下来我们通过一个逆序的循环,通过array_equal完成了模式匹配。

在回测中,我们可能需要一次性地提取出很长一段行情中所有的洗盘模式,并对其效果进行检验。上面的代码还可以通过numpy.lib.stride_tricks.sliding_window_view进行优化:


1
2
3
4
5
6
7
8
def feature_washout(bars):
    ...
    washouts = []
    for i, patten in enumerate(sliding_window_view(encoded, window_shape = 4)):
        if np.array_equal(patten, [1, -1, -1, 1]):
            washouts.append(i)

    return washouts

通过将涨跌幅二值化,我们就可以在随后方便地通过array_equal来匹配模式。我们这样做,是因为在这里定性分析基本就够了,只要涨跌幅超过5%,那么无论是跌了5.1%还是7.2%,我们都认为是洗盘。

但是,如果你觉得定量分析仍然有意义,也可以通过求皮尔逊相关系数的方法来进行模式匹配。

不过,被匹配的模式,应该使用多少呢?如果你对此感兴趣,可以评论区留言,获得推荐参数。

前视偏差 - 看似明白,实则糊涂

之前有一篇关于数据标注的笔记,得到了较多关注,也引起了一些同学质疑:

你使用了zigzag函数,这不会引起未来数据吗?

未来数据更学术化的说法叫前视偏差(look-ahead bias),回测中引入了未来数据,确实是做量化中很容易犯的一个错误。

这篇笔记解释了zigzag为什么用在标注中,不会产生未来数据。我们还列举了一些其它前视偏差的例子。这些是量化的经验之谈,来自实践,很少能在论文中看到。

Zigzag与 peak_and_valley_pivots

在之前的笔记中,我提到了使用zigzag函数来寻找k线中的波峰与波谷,并作为监督学习的标注数据。如果波峰记为1,波谷记为-1,其它的都记为0,则我们一共生成了三类标签。

这个标注数据还包含了原始的k线数据。因此,你可以基于这个数据集,构造自己的特征数据来训练模型,使之能预测一段行情的顶和底。

构建特征数据(因子)时,可以用RSI、均线拐头、上下影线、成交量放大、整数位等支撑、压力指标、压力线、支撑线等等。

数据标注使用zigzag包里的peak_and_valley_pivots函数。这个包可以通过以下命令进行安装:

1
pip install zigzag

peak_valley_pivots接受三个参数,第一个是要检测峰谷的时间序列,第二个参数用来设置下跌的幅度、第三个参数用来设置上涨的幅度。

也就是说,在序列\([t_0, t_1, t_2]\)中,如果\(th_1\)是下跌阈值,\(th_2\)是上涨阈值,则当 \(t_1 >= t_0 \times (1 + th_2)\) 并且 \(t_2 <= t_1 \times (1 + th_1)\)时,\(t_1\)就会被标记为波峰,如下图所示:

在Python中,还存在其它许多类似的库,最著名的是来自scipy.signals模块下的 find_peaks, find_peaks_cwt, argrelextrema 等。这些函数都要求我们至少设置判断峰谷的涨跌阈值(绝对值),有的还会允许设置驻点窗口大小。但是,zigzag 包中的peak_valley_pivots 方便之处在于,它不是通过绝对值来设置阈值,而是通过输入一个百分比来设置 -- 这是我们更常遇到的场景。

Tip

数字信号处理(Digital Signal Processing)在量化上有特殊的用途。文艺复兴早期在招人时,就很看重具有数字信号处理经验的人,他们从IBM viavoice团队挖了不少人。早期的声音识别是典型的数字信号处理应用,现在才全部转为深度学习。像傅立叶变换、小波变换等技巧,至今仍有不少论文在研究。

在具体使用peak_valley_pivots时,有两个简单的技巧。

首先,如何设置涨跌阈值?在实践中,我们常常先求得时间序列的每期涨跌幅。对股价波动而言,这是一个近似于平稳的序列。对这个序列求其标准差,±2倍标准差就可以作为阈值。

如果股价的涨跌近似于正态分布,那么如果t1超过t0达到2倍标准差的概率应该小于5%,把它认为是一个Outlier(离群值)显然是合适的(注意这里有很多近似处理的地方。严格来讲,股价涨跌近似于正态分布,并且股价超过平均值2倍标准差,概率才会小于5%)-- 换句话说,它就是我们要找的峰(或者谷)。

另一个技巧是,你必须理解peak_valley_pivots是如何处理头尾的数据的。

为什么说“zigzag会引起前视偏差”?

无论如何,peak_valley_pivots都在序列索引为0和-1的位置处,返回峰(1)或者谷(-1)的标签,无论这些点上的涨跌是否达到了阈值。这也是我们这篇笔记讨论前视偏差的起点。

我们再回顾一次之前的标注图。这一次,我们加入了一些序号以方便讨论。

在这个图中,peak_valley_pivots 对位置1和位置2都给出了标注,分别是-1和1。

但是,我们的标注工具没有显示位置2的标注。因为此时这个标注并不能固定下来。当我们投喂更多的数据时,我们发现,在位置2处的标注消失了(指peak_valley_pivots的返回结果,而非图中的显示),直到4月6日下午14:30分,peak_valley_pivots 才重新给出了标注(见位置3)。

这是我们在标注历史数据时会发生的情况。如果我们的标注工具是一次性地对一个非常长的序列进行的标注,那么我们将只会在头和尾遇到一次这样的问题(⚠️⚠️但是,此时阈值会在这个序列的全生命期上进行计算,这个阈值将会与只在近期较短一段时间上计算出来的不一致)。

在对数据进行分批标注时,数据被截断,从而引入了更多的头和尾,在这些边界上, peak_valley_pivots都给出标注,但往往是不稳定的(对开头而言,它很可能是错的或者多出来的)。但从倒数第二个标注起,它就已经被固定下来,不会变更。

这样会引起未来数据吗?

当然不会。这个标注过程完全正确。

⚠️但一些同学使用zigzag,并不是用来做数据标注的,而是用它来做回测的,这就会出现问题。⚠️

这个回测错误具体地说是这样产生的:在\(t_2\)时间点时,检测到了发生在\(t_1\)时间点上的一个峰,此时,如果按\(t_1\)的价格去卖出:

  1. 如果回测系统是正确的,模拟交易不可能完成。如果能够完成,意味着股价又返身向上了,此时在\(t1\)和现在的时间点\(t_0\)之间,已经出现一个谷底。这意味着我们把该持有的股票,错误地卖出了。
  2. 有的同学可能使用自己写的回测系统,比如,通过pandas dataframe来做向量回测,此时就非常容易引入错误,导致在\(t_0\)时间点时,回到\(t_1\)时间点,以该点时的价格,将股票卖出在最高点。

这是一个很容易理解,但又常常会隐藏在你的代码中的错误 -- 如果你不了解回测系统的运行原理的话。

Tip

既然zigzag的顶底标注不能用来预测,那么它还有用吗?答案是肯定的。虽然我们不能用zigzag来预测顶底,但是,它可以用来标注历史数据,以验证我们找出来的关于顶和底的特征是否属于高概率特征。

如果是,那么在实盘中,当这些特征再次出现时,我们就敢于预测,一个顶或者底出现了。

前视偏差常见的场景

产生前视偏差的场景很多。一般来说,它往往产生于数据的采集和发布过程,或者产生于加工处理方法。

比如,财务数据很容易产生前视偏差。财务数据常常以季度为单位进行“索引”。很自然地,财务数据的编制和发布时间要晚于这个“索引”时间。

以2019年一季度美国的宏观经济数据发布为例。GDP预估值发布于2019年4月25日;5月30日进行第一次修正;最终修正则是在当年的6月27日。这是正常和可预料的情况。

Tip

在回测和实盘中如何避免这种前视偏差?在我们的《量化二十四课》的第22课有详细说明。

财务造假也会造成前视偏差。举一个A股中真实的例子。某海产品养殖公司,2014,2015年连续两年亏损被ST,如果2016年再亏损,按当时规则将进入退市流程。于是,2017年3月,该公司公布了2016年年报,净利润7571万,扭亏为盈,成功保壳。2019年,最终查实他们虚增利润1.3亿,追溯修订2016年财报为亏损-5543万。

如果我们现在(2024年)运行回测,由于这些数据已经得到了修正,当回测运行到2017年3月,我们取得的财报数据将是-5543万,这会帮助我们在回测中避开这个雷;但在2017年5月,实盘中获取到的该公司上年净利润为7571万。但你的模型在实盘中无法避开这种雷。

其它引起前视偏差的典型场景还有:

  • 前复权
  • 引用错误
  • 偷价
  • 统计函数如max、min、rank等,也包括zigzag类的函数

除了前视偏差,我们在回测中还可能遇到幸存者偏差、过度拟合、冲击成本、交易容量不足、回测时长不足、交易规则错误等各种偏差。这些都是只有在实战中才能获得的经验,我们在《量化二十四课》中都有介绍,可以帮你迅速提升经验值,由量化萌新成长为量化高手。

你也可以继续关注本号,我们后续会有机会深入讲解这些概念。

封面故事

封面是石溪大学的Charles & Wang中心,由美籍华人、亿万富翁、CA科技创始人王嘉廉捐助修建,是一座帮助人们了解亚洲文化和世界其它文化相互作用的建筑。

该建筑由砖块和白色半透明玻璃组成,象征着中国传统建筑中的窗楹蒙纸,此外还有一座带台阶的拱桥,让人联想到中国的寺庙。其内部有一个供学生使用的东亚美食广场,以便让人了解东亚、特别是中国的美食文化。

石溪大学与华人很有缘。杨振宁在此执教37年。丘成桐在此担任过助教。陈省身则是石溪的荣誉博士。

石溪大学出了很多名人,共拿了至少8个诺奖。量化教父James Simons则曾任该校数学系主任。