第一章:策略核心原理
做量化交易这些年,我见过太多人一上来就撸代码、跑回测,结果亏得底裤都不剩。为什么?说白了,策略的原理没吃透。今天咱们就从最经典的配对交易开始,把地基打牢。
1.1 配对交易的基本逻辑
配对交易,英文叫Pairs Trading。它的核心思想很简单:找到两只走势高度相关的股票,当它们的价格出现偏离时,做多弱的、做空强的,赌它们会回归。
我刚开始接触这个策略时,觉得这不就是「高抛低吸」吗?后来发现,没那么简单。你想想看,如果两只股票的相关性只是巧合,那你就等着被市场教育吧。
配对交易的底层逻辑,建立在三个假设上:
- 长期均衡关系:两只股票的价格存在某种稳定的数学关系
- 短期偏离可逆:一旦偏离,市场力量会把它拉回来
- 对冲风险:多空组合能抵消大盘波动的影响
嗯,这里要注意。不是随便找两只同行业的股票就能做配对。我踩过这个坑——曾经把茅台和五粮液做配对,结果发现它们的价差序列根本不平稳。后来才明白,协整检验才是王道。
1.2 价差序列的构建
价差序列,就是配对交易的核心数据。怎么构建?通常有两种方法:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| 简单价差 | spread = P_A - β × P_B | 两只股票价格量级相近 |
| 标准化价差 | spread = (P_A / P_B) - 1 | 价格差异较大时 |
我个人习惯用简单价差,但前提是β要算准。β怎么算?用OLS回归。代码长这样:
import numpy as np
import statsmodels.api as sm
# 假设 price_a 和 price_b 是两列价格序列
X = sm.add_constant(price_b)
model = sm.OLS(price_a, X).fit()
beta = model.params[1] # 这就是我们要的β
# 构建价差
spread = price_a - beta * price_b
我在项目中遇到过一个问题:β不是一成不变的。市场环境变了,β也会漂移。所以,我建议用滚动窗口来动态计算β,窗口大小一般选60到120个交易日。
1.3 均值回归假设
价差序列构建好了,接下来要验证它是不是均值回归的。说白了,就是看这个序列会不会「弹回来」。
怎么验证?最常用的方法是ADF检验。如果检验结果显著,说明序列是平稳的,均值回归假设成立。
from statsmodels.tsa.stattools import adfuller
result = adfuller(spread)
p_value = result[1]
if p_value < 0.05:
print("序列平稳,均值回归假设成立")
else:
print("序列不平稳,别做配对交易")
我曾经犯过一个错误:只看ADF检验的p值,忽略了序列的波动性。结果呢?价差确实回归了,但波动太大,止损被打穿了。所以,我建议你同时看序列的标准差,确保波动在可接受范围内。
我曾经用日线数据做ADF检验,结果很漂亮。但换成小时线数据,p值直接翻倍。不同时间频率下,平稳性可能完全不同。建议多频率验证。
1.4 Z-Score与交易信号生成
有了价差序列,怎么判断什么时候该进场?Z-Score就是我们的信号灯。
Z-Score的计算公式:
z_score = (当前价差 - 价差均值) / 价差标准差
当Z-Score的绝对值大于某个阈值时,我们就认为价差偏离到了极端位置,可以开仓了。
阈值怎么设?我一般用±2。为什么?因为正态分布下,Z-Score超过±2的概率只有5%左右。这意味着,我们只在「小概率事件」发生时出手。
交易信号的逻辑:
- Z-Score > 2:价差过高,做空价差(卖A买B)
- Z-Score < -2:价差过低,做多价差(买A卖B)
- Z-Score 回归到 0 附近:平仓离场
你想想看,这个逻辑是不是很直观?但实际跑起来,问题就来了。阈值设得太小,交易太频繁,手续费吃掉利润;设得太大,一年开不了几次仓,资金利用率低。
阈值不是死的。我建议用动态阈值,比如根据近期波动率调整。波动率大的时候,阈值放大到2.5;波动率小的时候,缩到1.8。这样能适应不同的市场状态。
最后,咱们用一张图来总结配对交易的核心流程:
这张图把整个流程串起来了。从选标的到生成信号,每一步都环环相扣。你想想看,如果中间任何一环出了问题,整个策略就废了。
好了,这一章的内容就到这儿。记住一句话:策略原理是根,代码是叶。根扎得深,叶子才能茂盛。