今天要聊的是 Alpha 101 系列中的第 3 个因子,公式是:
Alpha#3 = -1 × correlation(rank(open), rank(volume), 10)这玩意儿看起来又是个典型的Alpha,各种rank、各种correlation、一堆负号,但我真心觉得它有点东西。虽然你可能第一眼觉得它像是某种工业垃圾因子(其实Alpha 101里不少长这样),但别急,细嚼慢咽一下,它比你想象得聪明。
因子拆解
先拆一拆结构,没那么复杂:
rank(open):开盘价做了个横向排名,标准化处理,防止极端值影响。rank(volume):同理,对成交量进行横向排名。correlation(…, 10):过去10天里两个序列之间的皮尔逊相关性。- 最后乘个负号:反向思维,低相关越好,或者说负相关越强,分数越高。
所以这个因子的核心想法是:
在过去10天里,开盘价的排名和成交量的排名之间的相关性越低(最好是负相关),这个因子的值就越大。
注意,这里不是说开盘价和成交量的值,而是它们的“相对位置”是否联动。这其实挺有意思的,它在追踪一种“非共振”的状态。
Alpha #3因子在捕捉量价不同步信号
我个人是这么理解这个因子的:它试图去抓住市场中那些价格和量不同步的时刻。
当一只股票开盘价很高,但量却排在低位,或者反过来,说明有点“意外”——可能是资金还没反应过来、也可能是有些投资者在悄悄布局。这种状态下,主力还没发力,但价格已经先动了,或者量突然异常,但价格没跟上。
这种错位感,我特别喜欢。它不追求“高量高价”这种大家都看到的机会,而是去找那些还没被定价机制完全消化的信息,这在短线交易中是很宝贵的。
说得再直白一点:
- 相关性高:说明市场在一个“共识环境”下运作,该涨的涨,该量的量,没啥特别。
- 相关性低甚至为负:可能是预示某种反转、突发事件、结构性分歧,市场还没定好方向。
这个因子在小市值 + 波动股里比较有戏
坦白说,如果你把这个因子丢到全市场里跑,表现未必惊艳。但当我把它筛选在一些波动大的小票里(特别是那些隔夜容易受消息冲击的品种),它的信号就相当敏感。
比如某只小票在开盘前出个模糊利好,结果开盘价格被抬高了,但市场大部分人还没搞清楚消息真假,成交量没怎么放出来。这时候rank(open)拉高但rank(volume)不跟,correlation就会拉低,Alpha#3 给出一个不错的提示信号。
不过实话实说,这个因子不太适合中长周期,它的“有效信息”窗口很短,甚至1~3天后就没啥用了。你要真拿它去做30日持有期,那是用手榴弹钓鱼——浪费。
一点吐槽
我得说实话,这个因子是典型的“工具性”因子,不太会成为明星选手,但它作为信号融合的一环非常有价值。它没啥想象空间,不像动量类因子或者盈利修复类因子能讲大故事。
它适合混合因子池里补盲区,比如你组合里动量、反转、估值都有了,但就是缺一个状态检测器,它就能提醒你某只票最近的量价关系有点古怪,值得看看。
我会把这个因子定义为一种情绪混乱探测器。它不预测未来,也不评估基本面,它只是说:
过去10天,这票的开盘价和成交量有点不同步,可能有事。
你拿它做主力因子可能不够力,但如果你是一个多因子模型构建者,或者你和我一样喜欢捕捉市场异象,这个因子值得拥有姓名。
import pandas as pd
import numpy as np
from scipy.stats import rankdata
def rank_series(series):
"""对 Series 做横向排名,按时间点逐个 rank"""
return series.rolling(window=1).apply(lambda x: rankdata(x)[-1], raw=True)
def rolling_corr(series1, series2, window):
"""计算两个序列的滚动相关性"""
return series1.rolling(window).corr(series2)
def alpha_3(df, window=10):
"""
Alpha#3 = -1 * correlation(rank(open), rank(volume), 10)
输入: df 包含 open 和 volume 两列
输出: 一个新的 Series,表示该因子的值
"""
# 横向排名
rank_open = df['open'].rank(axis=0, method='average', pct=True)
rank_volume = df['volume'].rank(axis=0, method='average', pct=True)
# 滚动相关性
corr = rolling_corr(rank_open, rank_volume, window)
return -1 * corr
# 示例:构造数据
# 假设你有一个 DataFrame,列名为 open, volume,索引是日期
data = {
'open': [10, 10.5, 10.7, 10.1, 10.3, 10.6, 10.4, 10.9, 11.0, 11.1, 11.3],
'volume': [1000, 1100, 900, 950, 980, 1030, 990, 1020, 1005, 1010, 1070],
}
df = pd.DataFrame(data)
df['alpha_3'] = alpha_3(df)
print(df)