23. 基差交易的量化因子库:动量因子、反转因子、波动率因子、流动性因子在基差中的表现
做基差交易这些年,我越来越觉得,因子就是你的眼睛。没有因子,你就是在黑箱里瞎摸。今天咱们把这四个核心因子——动量、反转、波动率、流动性——在基差里的表现,掰开揉碎了讲清楚。
核心观点:基差因子不是孤立存在的。它们之间会互相干扰,也会互相强化。我习惯把它们组合成一个「因子矩阵」来用,而不是单独看某一个。
23.1 动量因子:趋势是你的朋友,但别太晚下车
动量因子在基差交易里,说白了就是追涨杀跌。但这里的「涨跌」不是价格,而是基差本身的变化率。
我个人习惯用过去N期的基差变化率来构建动量信号。比如,过去5天基差持续走阔,我就认为动量向上,做多基差;反之做空。
# 动量因子计算示例
def momentum_factor(basis_series, window=5):
"""
计算基差的动量因子
basis_series: 基差时间序列
window: 动量窗口
"""
# 计算基差变化率
basis_returns = basis_series.pct_change()
# 滚动求和作为动量信号
momentum = basis_returns.rolling(window).sum()
return momentum
嗯,这里要注意:动量因子的窗口选择非常敏感。我在实盘里试过,短窗口(3-5天)容易产生假信号,长窗口(20天以上)又太滞后。我个人觉得,10天左右是个不错的平衡点。
避坑指南:我曾经在螺纹钢的跨期套利上,用5天动量信号做多,结果连续被止损了3次。后来发现,那段时间市场在震荡,动量因子完全失效。所以,动量因子在趋势行情里好用,震荡行情里就是个坑。
23.2 反转因子:均值回归,但别跟趋势对着干
反转因子,就是赌基差会回到均值。你想想看,基差不可能无限扩大或缩小,总有回归的时候。但问题是——什么时候回归?
我常用的反转因子是基差偏离度:
def reversal_factor(basis_series, window=20):
"""
计算基差的偏离度(反转因子)
"""
mean = basis_series.rolling(window).mean()
std = basis_series.rolling(window).std()
# Z-score 标准化
z_score = (basis_series - mean) / std
return z_score
当Z-score超过2或低于-2时,我就认为基差过度偏离,存在反转机会。但说实话,这个阈值不是固定的。不同品种、不同市场环境下,阈值差异很大。我习惯用动态阈值,比如根据历史分位数来定。
警告:反转因子最大的风险是「趋势延续」。如果市场出现了结构性变化(比如政策突变、交割规则调整),基差可能不会回归,反而越走越远。我吃过这个亏,2019年在铁矿石上,基差偏离了4个标准差还没回来,最后被迫止损。
23.3 波动率因子:高波动是机会,也是陷阱
波动率因子,衡量的是基差的不确定性。我个人觉得,波动率是基差交易的「放大器」——它不直接告诉你方向,但告诉你机会的大小和风险的高低。
我常用的波动率指标是历史波动率(HV)和已实现波动率(RV):
def volatility_factor(basis_series, window=20):
"""
计算基差的波动率因子
"""
# 计算对数收益率
log_returns = np.log(basis_series / basis_series.shift(1))
# 滚动标准差(年化)
volatility = log_returns.rolling(window).std() * np.sqrt(252)
return volatility
为什么波动率重要?因为高波动环境下,基差更容易出现极端值,这给反转因子提供了机会。但同时,高波动也意味着止损需要设得更宽,否则容易被震出去。
我的经验:当波动率处于历史低位时,我倾向于使用动量因子;当波动率处于历史高位时,我倾向于使用反转因子。说白了,就是「低波动追趋势,高波动赌回归」。
23.4 流动性因子:没有流动性,一切都是空谈
流动性因子,可能是最容易被忽视的。你想想看,就算你识别出了完美的套利机会,但如果市场深度不够,你根本进不去,或者进去了出不来。
我衡量流动性主要看三个指标:
| 指标 | 计算方法 | 在基差交易中的意义 |
|---|---|---|
| 买卖价差 | ask - bid | 价差越大,交易成本越高,侵蚀套利利润 |
| 市场深度 | 盘口前5档的总挂单量 | 深度不足时,大单会引发滑点 |
| 成交量 | 过去N分钟的累计成交量 | 成交量萎缩时,基差容易被操纵 |
def liquidity_factor(bid_ask_spread, depth, volume):
"""
综合流动性评分
"""
# 标准化处理
spread_score = 1 / (1 + bid_ask_spread)
depth_score = np.log1p(depth)
volume_score = np.log1p(volume)
# 加权综合
liquidity_score = 0.3 * spread_score + 0.4 * depth_score + 0.3 * volume_score
return liquidity_score
避坑指南:我曾经在临近交割日时,发现一个基差机会特别好,但没注意流动性。结果一进场,直接把基差打穿了,反而亏了钱。从那以后,我给自己定了个规矩:流动性评分低于0.6的品种,坚决不碰。
23.5 因子组合:1+1>2 的艺术
单独看任何一个因子,都有局限性。我习惯把它们组合成一个多因子信号:
def combined_signal(momentum, reversal, volatility, liquidity):
"""
多因子组合信号
"""
# 动量信号(-1到1)
m_signal = np.clip(momentum, -1, 1)
# 反转信号(-1到1)
r_signal = np.clip(-reversal, -1, 1) # 反转信号取反
# 波动率调节(0到1)
v_weight = 1 - np.clip(volatility / 0.5, 0, 1) # 低波动时权重高
# 流动性过滤
l_filter = (liquidity > 0.6).astype(int)
# 组合信号
final_signal = (0.4 * m_signal + 0.3 * r_signal) * v_weight * l_filter
return final_signal
这个组合的逻辑是:动量给方向,反转给边界,波动率调权重,流动性做过滤。说白了,就是让四个因子各司其职,互相制约。
重要提醒:因子组合不是一成不变的。不同品种、不同市场环境下,因子的权重需要动态调整。我习惯用滚动窗口的因子IC值来动态分配权重——哪个因子最近表现好,就给它更高的权重。
23.6 知识体系框架
下面这张图,是我自己总结的基差因子体系。你看一眼,就能明白这四个因子是怎么协同工作的:
你看,这个体系其实不复杂。核心就是让每个因子发挥自己的特长,然后通过组合来弥补各自的短板。我在实盘里用了两年多,效果还不错。
最后说一句:因子库不是建完就完事了。市场在变,因子的表现也在变。我每个月都会重新跑一遍因子IC测试,看看哪些因子失效了,哪些因子变强了。说白了,因子库需要持续维护,就像养花一样,得定期浇水施肥。