延续上次的思路,今天继续更新【101个量化因子系列】。

每篇一因子,一起拆公式、聊逻辑、挖一挖背后的交易思路。

这次轮到Alpha#2,它的公式是这样的:

Python

Alpha#2 = (-1 * correlation(rank(delta(log(volume), 2)), rank(((close - open) / open)), 6))

是不是又有点眼晕?没关系,咱们还是老规矩——慢慢拆开来看。

其实这个因子的核心思路,比上次的Alpha#1还要直白一些。

一步步拆开来看

首先,注意这个因子里有两个主要部分,它们之间算的是相关性(correlation)

  • 第一部分是:rank(delta(log(volume), 2))
  • 第二部分是:rank((close - open) / open)

它们分别是什么意思呢?

第一部分:成交量变化

log(volume) —— 取成交量的对数,这样可以让成交量数据分布更平滑(避免个别超级大单影响太大)。

delta(log(volume), 2) —— 计算2天前今天成交量对数的变化,也就是变化率。

然后再 rank 一下,做归一化排序,便于跟别的量进行比较。

简单理解:最近2天内成交量变化的强弱排名

第二部分:日内收益率

(close - open) / open —— 这是标准的日内涨跌幅,表示当天涨了还是跌了、涨跌幅度多大。

同样也是 rank 一下,保证量纲一致,适合做后面的相关性计算。

简单理解:当天价格涨跌的强弱排名

把两部分连起来

接下来是 correlation(..., ..., 6)

也就是拿上面这两组数据,在6天的窗口里算它们的皮尔逊相关系数。

最后乘一个 -1,取负号。

总结一下,这个因子本质上是在看:

  • 最近6天里,成交量变化日内涨跌 的关系是怎样的?
  • 如果成交量突然增加,价格却不涨,那就是弱;
  • 如果成交量增加,价格也跟着涨,就是强;
  • 最后取负号,是为了让弱的情况分数高(负相关高打分)。

所以,Alpha#2想找什么股票?

它倾向于挑出那些:

  • 最近成交量突然异动
  • 但价格却没有明显跟涨的股票

因为这类股票可能被低估、或者潜藏着滞后上涨的机会。

也可以理解为:

量价背离,预示着潜在的交易机会。

代码示例

Python
import pandas as pd
import numpy as np

# 假设我们有一个包含股票数据的 DataFrame,包含 'date', 'open', 'close', 'volume' 等列
# 行情数据由Infoway API提供:www.infoway.io
# 这里我们创建一个示例数据框
data = {
    'date': pd.date_range('2025-01-01', periods=10, freq='D'),
    'open': [100, 102, 104, 105, 106, 107, 108, 110, 112, 113],
    'close': [101, 103, 105, 106, 107, 109, 110, 113, 114, 115],
    'volume': [10000, 11000, 12000, 11500, 13000, 12500, 14000, 14500, 15000, 15500]
}

df = pd.DataFrame(data)

# 计算成交量的对数
df['log_volume'] = np.log(df['volume'])

# 计算成交量对数的变化率
df['delta_log_volume'] = df['log_volume'].diff(2)

# 计算日内涨跌幅
df['daily_return'] = (df['close'] - df['open']) / df['open']

# 计算成交量变化率和日内涨跌幅的排名
df['rank_delta_log_volume'] = df['delta_log_volume'].rank()
df['rank_daily_return'] = df['daily_return'].rank()

# 计算6天窗口的相关性
# 我们计算过去6天(包括今天)的排名之间的皮尔逊相关系数
df['correlation'] = df['rank_delta_log_volume'].rolling(window=6).corr(df['rank_daily_return'])

# 计算Alpha#2(取负相关性)
df['alpha2'] = -df['correlation']

# 查看结果
print(df[['date', 'alpha2']])
  1. 计算对数成交量np.log(df['volume']),我们对成交量取对数,目的是减少量级的差异。
  2. 计算成交量变化率df['log_volume'].diff(2),这行代码计算的是成交量对数在过去2天的差异,即delta(log(volume), 2)
  3. 计算日内涨跌幅(df['close'] - df['open']) / df['open'],计算每个交易日的日内涨跌幅。
  4. 我们分别对成交量变化率和日内涨跌幅进行排名,通过rank()函数来实现。
  5. df['rank_delta_log_volume'].rolling(window=6).corr(df['rank_daily_return']),这行代码计算的是过去6天内这两列排名的皮尔逊相关系数。rolling(window=6)表示6天窗口。
  6. 我们最后取负相关性(df['correlation'])得到 Alpha#2 的值。

可能的改进方向

我们也可以思考一下怎么优化这个因子:

1. 调整窗口期

  • 现在默认相关性是6天窗口,但不同市场节奏不同。
  • 可以试着改成5天、10天,或者用滑动平均来平滑波动。

2. 换其他的量价指标

  • 日内涨跌可以换成其他更敏感的指标,比如当天最高价和开盘价之差(high – open)。
  • 成交量变化也可以引入量比(volume ratio)等更细腻的指标。

3. 分组测试

  • 按市值分组(大盘、小盘)看看这个因子在不同类型股票里的表现是否一致。
  • 也可以按行业分组,比如周期股、科技股的量价关系往往不一样。

小结一下

Alpha#2虽然公式看起来复杂,但核心逻辑其实是很实在的:

观察成交量和价格之间的微妙关系,挖掘被市场忽视的潜在机会。

接下来,如果你感兴趣,也可以自己动手改一改,

比如换窗口期、换量价指标、分组测试……

相信你一定能找到更适合自己市场和策略的版本!