okaa

量化全流程:配对策略的python回测

这篇文章包括了从对原始数据处理、数据检验、代码实现的一系列详细步骤,如果你没有量化交易的经验,这篇文章是一个很好的开始。

配对策略属于均值回归策略的一种,主要从两只股票的价差来盈利。这个策略在市场上存在已久,但时至今日依然奏效。

第一个使用这个策略的人是利弗莫尔,对就是《股票大作手回忆录》的主人公,他用肉眼观察同类资产的表现。

在进入这个策略之前,需要区分两个统计学概念:相关性和协整性。

相关性 Correlation:

p=1,两组数据完全正相关
p=-0.7,两组数据高度负相关
p=0.7,两组数据高度正相关

协整性 Cointegration:

配对策略:

两只股票具有高度协整关系,那么他们的价差长期来看会比较稳定,但稳定性会因为投资者“追涨杀跌”等等的不理性交易而打破,导致价差扩大

配对交易就从这个价差切入,分别在两只股票上建立多头和空头头寸,卖空相对高估的股票,买入相对低估的股票,等待价差收敛。

配对交易同时双向建仓,对冲掉了绝大部分市场风险,因此属于市场中性策略。

开搞:

资产选择:澳大利亚ETF(EWA)和加拿大ETF(EWC)。

先来看看他俩价格之间的相关性,一眼看上去高度相关:

EWC和EWA之间的相关性

用代码测试一下:

import numpy as np
np.corrcoef(Asset_1, Asset2)

输出结果是0.85,验证了高度正相关的猜想。

再来看看这两组数据的比值是否平稳,如果数据随着时间变化,有趋势性和季节性,那么数据就不平稳,对于不平稳的数据,发现其中规律就无从谈起了。

两组数据的比值进行平稳性检验:

def stationarity(ratio, cutoff = 0.05):
Data[:, 2] = Asset_2 / Asset_1
Ratio = Data[:, 2]
a = np.ravel(ratio)
if adfuller(a)[1] < cutoff:
print(‘The series is stationary’)
print(‘p-value = ‘, adfuller(a)[1])

p-value=0.032,数据平稳

EWA和EWC的比值

下一步检查他们的协整性,高度协整性意味着均值回归,是执行配对策略的基础。

def cointegration(a, b):
if coint(a, b)[1] < 0.05:
print(‘The series are cointegrated’)
print(‘p-value = ‘, coint(a, b)[1])
else:
print(‘The series are NOT cointegrated’)
print(‘p-value = ‘, coint(a, b)[1])
cointegration(Asset_1, Asset_2)

协整性的p-value为0.048,说明数据高度协整,存在均值回归性质。

现在对数据的比值进行标准化处理:

for i in range(len(Data)):
try:
Data[i, 3] = (Data[i — lookback:i + 1, 2].mean())
except IndexError:
pass
# 计算标准差
for i in range(len(Data)):
Data[i, 4] = ((Data[i — lookback:i + 1, 2].std()))
# 标准化
for i in range(len(Data)):
Data[i, 5] = (Data[i, 2] — Data[i, 3]) / Data[i, 4]

经标准化处理后的比值。选择-2和2作为界限,当比值达到2,做空;当比值达到-2,做多。

然后开始回测,回测的时间为过去9年的历史行情,策略代码如下:

for i in range(len(Data)):
try:
if Data[i, 2] <= lower_barrier and Data[i — 1, 2] > lower_barrier:
Data[i + 1, 4] = -1
Data[i + 1, 5] = 1
elif Data[i, 2] >= upper_barrier and Data[i — 1, 2] < upper_barrier:
Data[i + 1, 6] = 1
Data[i + 1, 7] = -1
else:
continue
except IndexError:
pass
for i in range(len(Data)):
try:
if Data[i, 5] == 1:
Data[i + holding_period, 8] = (Data[i + holding_period, 1] — Data[i, 1])
if Data[i, 6] == 1:
Data[i + holding_period, 8] = (Data[i + holding_period, 0] — Data[i, 0])
if Data[i, 4] == -1:
Data[i + holding_period, 9] = (Data[i, 0] — Data[i + holding_period, 0])
if Data[i, 7] == -1:
Data[i + holding_period, 9] = (Data[i, 1] — Data[i + holding_period, 1])
except IndexError:
pass

策略触发的信号,红点为卖点,绿点为买点。

回测结果:

注意,这个策略没有把手续费和其他交易成本(比如冲击成本)考虑在内,也没有加杠杆。

最后总结一下配对策略的实现过程:

  1. 找到两组逻辑上相关的资产,观察一下他们的收益率或者价格曲线,对直觉上相关的两组资产进行相关性检验。
  2. 如果两组资产接近正相关,下一步进行价格比值收益率比值的平稳性检验
  3. 平稳性满足后,进行协整性检验。
  4. 如果数据高度协整,就可以进行数据回测了。

这个策略在数据预处理阶段的三个概念:相关性,协整性,平稳性,在后面的策略中会是常客:

  1. 相关性:两个变量线性相关程度
  2. 协整性:两个变量的比值,是不是围绕某个定值波动
  3. 平稳性:不随时间变化的数据

退出移动版