注:只是先记下来,怕忘了
i | x | y |
1 | 25 | 110 |
2 | 27 | 115 |
3 | 31 | 155 |
4 | 33 | 160 |
5 | 35 | 180 |
均值(MA),不解释
方差,序列,减均值的平方(有正有负,平方更好计算),除以序列长度(元素个数)
标准差,方差开平方(一倍标准差 68.3% 二倍标准差95.5% 三倍标准差 99.7%)
两组序列的关系的判定
1、求线性回归 y=kx+b,其中 x,y 分别为两组序列
2、最基本的方法就是做最小二乘法(SLOP斜率,截距) slope, intercept = np.polyfit(x, y, 1)
3、也可看两个序列的相关系数(R2)np.corrcoef(x,y)[0,1]
4、对异常点的判断,点距离直线的距离(欧氏距离)
5、zscore 这个点离最中心的点(预测点)有几倍的标准差(可以为正为负)z = stats.zscore(x)
一般来说说,超过2倍标准差的就很远啦(落在两倍标准差的概率为95.5%)
线性回归(Linear Regression):
Y与X的关系满足直线方程,Y=a+bX+e
( a为截距,b为斜率Slope,e为误差项),
上述方程由最小二乘法得出。
什么是线性回归/拟合相关系数R2:
评估拟合的线性度偏差的置信度系数。
一般来说,在slope相等时,
R2越大,说明拟合的线性度越高,其上限是1.
价格的归一化
股票的价格变化范围不尽相同,直接使用原始价格无法有效地显示出股票之间的相对价格并进行比较。所以我们首先需要对原始价格进行变换,构造出具有一致性的可以在不同股票对之间进行等价比较“正则价格”,例如如下三种构造方式。
1.Standardized Prices:
P~t=Pt−μPsP (1)
其中 μp 是价格序列的平均值, sP 是标准方差。
2.Scaled Prices:
P~t=PtP0 (2)
其中 P0 是价格序列的初始值。
3.Scaled Cumulative Return Index:
P~t=RtR0 (3)
其中 Rt 是累积收益, RO 是初始值。
import numpy as np
from statsmodels.tsa.stattools import coint
from statsmodels.tsa.stattools import adfuller
平稳性检验:Augmented Dickey Fuller(ADF) adfuller函数
相关性检验:R2相关性检验 np.corrcoef
协整:coint函数
协整
是一种比相关更微妙的关系。如果两个时间序列是协整的,那么一定存在它们的某个线性组合,围绕着其平均值在较小范围内波动。用数学的语言说,在所有的时间点上,这个线性组合构成的新随机变量服从相同的概率分布
在时间序列分析中,当两条dd次差分后平稳的序列(both integrated of order d,I(d) )能够通过线性组合的形式产生一条 (d−b) 次差分后平稳的序列,我们称这两条序列具有协整关系(cointegration)。
协整(Cointegration)理论是恩格尔(Engle)和格兰杰(Granger)在1978年提出的。平稳性是进行时间序列分析的一个很重要的前提,很多模型都是基于平稳下进行的,而现实中,很多时间序列都是非平稳的,所以协整是从分析时间序列的非平稳性入手的。
蓝色曲线:X股票的日收益服从正态分布,然后我们画出它的累积收益图
黄色曲线:构造出来的
由于我们假定Y与X有很强的联系,所以Y的价格应该与X高度相关。我们不妨对X添加一点噪声(可用正态分布),从而得到Y的价格(黄色曲线)
上面我们其实已经构建了两个协整序列的例子,让我们下面将X和Y的价差绘图展示。
折线是X和Y的价差,虚线为价差的平均值。可以看到,折线在虚线两侧波动
协整 VS 相关
协整和相关,概念上容易混淆,但它们并不相同。为了阐明它们的区别,我们来看看协整但不相关,和相关但不协整的例子。
相关但不协整:下面是两个正态分布所生成的随机数的累加序列。它们高度相关,但协整检验的p值大于0.05,未能通过检验(看起来差不多,其实没啥内在的关系)协整但不相关
Xruns = np.random.normal
yrurs = np.random.normal
pd.concat
plt.xlim
协整但不相关 的例子相对更难构造一些,我们来看下面的正态分布序列和方波序列。两个序列的相关性非常非常低,但!是! ——协整检验的p值竟然几乎为0:这说明它们一定存在一个能保持“平稳”的线性组合,我们自然会想找到这个线性组合。
我们引入了沪深300指数,即把市场因素也纳入我们的数据集中。这是因为市场会使很多股票的价格漂移趋势相似,以至于你会觉得两只股票很像是协整的,但实际上只是因为它们都与市场协整。也就是说,市场因素是一个“混淆变量”:与其他变量都有关系的变量,导致我们想考察的变量间出现虚假关系。因此不管你得到什么样的关系,记得检查是不是市场因素在“作祟”
由上面的热力图,我们看到有两组具有协整关系的序列对。在排除市场因素影响之后,我们认为'600230.XSHG'和'601966.XSHG',即沧州大化和玲珑轮胎是具有协整关系
关于热力图另一个例子
['000001.XSHE', '002142.XSHE', '002807.XSHE', '600000.XSHG', '600015.XSHG', '600016.XSHG', '600036.XSHG', '600908.XSHG', '600919.XSHG', '600926.XSHG', '601009.XSHG', '601128.XSHG', '601166.XSHG', '601169.XSHG', '601229.XSHG', '601288.XSHG', '601328.XSHG', '601398.XSHG', '601818.XSHG', '601838.XSHG', '601939.XSHG', '601988.XSHG', '601997.XSHG', '601998.XSHG', '603323.XSHG']
closetable=DataAPI.MktEqudGet(tradeDate=u"",secID='000001.XSHE',ticker=u"",beginDate=u"20170101",endDate=u"20180101",isOpen="",field=u"tradeDate,closePrice",pandas="1")
closetable.index=pd.to_datetime(closetable.tradeDate)
del closetable['tradeDate']
closetable.columns=['000001.XSHE']
for i in ['002142.XSHE', '002807.XSHE', '600000.XSHG', '600015.XSHG', '600016.XSHG', '600036.XSHG', '600908.XSHG', '600919.XSHG', '600926.XSHG', '601009.XSHG', '601128.XSHG', '601166.XSHG', '601169.XSHG', '601229.XSHG', '601288.XSHG', '601328.XSHG', '601398.XSHG', '601818.XSHG', '601838.XSHG', '601939.XSHG', '601988.XSHG', '601997.XSHG', '601998.XSHG', '603323.XSHG']:
dt=DataAPI.MktEqudGet(tradeDate=u"",secID=i,ticker=u"",beginDate=u"20170101",endDate=u"20180101",isOpen="",field=u"tradeDate,closePrice",pandas="1")
dt.index=pd.to_datetime(dt.tradeDate)
closetable[i]=dt.closePrice
closetable.head()
tradeDate | 000001.XSHE | 002142.XSHE | 002807.XSHE | 600000.XSHG | 600015.XSHG | 600016.XSHG | 600036.XSHG | 600908.XSHG | 600919.XSHG | 600926.XSHG | ... | 601288.XSHG | 601328.XSHG | 601398.XSHG | 601818.XSHG | 601838.XSHG | 601939.XSHG | 601988.XSHG | 601997.XSHG | 601998.XSHG | 603323.XSHG |
2017/1/3 | 9.16 | 17.4 | 11.03 | 16.3 | 11.14 | 9.11 | 17.96 | 11.07 | 9.75 | 21.13 | ... | 3.12 | 5.81 | 4.43 | 3.95 | NaN | 5.49 | 3.47 | 16.27 | 6.75 | 15.68 |
2017/1/4 | 9.16 | 17.51 | 11.04 | 16.33 | 11.2 | 9.11 | 18.02 | 11.12 | 9.8 | 21.31 | ... | 3.12 | 5.82 | 4.43 | 3.96 | NaN | 5.49 | 3.47 | 16.32 | 6.75 | 15.57 |
2017/1/5 | 9.17 | 17.32 | 11.02 | 16.3 | 11.12 | 9.08 | 18.1 | 11.09 | 9.74 | 21.2 | ... | 3.13 | 5.8 | 4.44 | 3.94 | NaN | 5.49 | 3.46 | 16.3 | 6.79 | 15.55 |
2017/1/6 | 9.13 | 17.25 | 10.85 | 16.18 | 11.01 | 9.01 | 17.96 | 10.88 | 9.63 | 20.88 | ... | 3.13 | 5.78 | 4.44 | 3.92 | NaN | 5.46 | 3.44 | 15.88 | 6.79 | 15.33 |
2017/1/9 | 9.15 | 17.51 | 10.8 | 16.2 | 11.07 | 9.02 | 17.94 | 10.8 | 9.66 | 20.94 | ... | 3.13 | 5.79 | 4.46 | 3.92 | NaN | 5.47 | 3.44 | 15.97 | 6.84 | 15.12 |
corr=closetable.corr()
sns.heatmap(corr,vmax=1,vmin=-1,linewidth=0.5)
for i in ['000001.XSHE', '002142.XSHE', '002807.XSHE', '600000.XSHG', '600015.XSHG', '600016.XSHG', '600036.XSHG', '600908.XSHG', '600919.XSHG', '600926.XSHG', '601009.XSHG', '601128.XSHG', '601166.XSHG', '601169.XSHG', '601229.XSHG', '601288.XSHG', '601328.XSHG', '601398.XSHG', '601818.XSHG', '601939.XSHG', '601988.XSHG', '601997.XSHG', '601998.XSHG', '603323.XSHG']:
for j in ['000001.XSHE', '002142.XSHE', '002807.XSHE', '600000.XSHG', '600015.XSHG', '600016.XSHG', '600036.XSHG', '600908.XSHG', '600919.XSHG', '600926.XSHG', '601009.XSHG', '601128.XSHG', '601166.XSHG', '601169.XSHG', '601229.XSHG', '601288.XSHG', '601328.XSHG', '601398.XSHG', '601818.XSHG', '601939.XSHG', '601988.XSHG', '601997.XSHG', '601998.XSHG', '603323.XSHG']:
if corr[i][j]>0.95 and i!=j:
print [i,j]
closetable[['601288.XSHG','601398.XSHG','601939.XSHG']].plot(figsize=(8,6))
农业银行、工商银行、建设银行
universe= ['601288.XSHG','601398.XSHG','601939.XSHG']
线性回归也能用于估计参数并检验序列的协整性,这种方法在计量经济学中被称作Engle-Granger方法(我们一般简称E-G两步法)
判断时间序列对(组)之间是否存在协整性一般有三种方法,
(1) Engle-Granger method;
(2) Phillips-Ouliaris methods;
(3) Johansen’s procedure.
以一组序列对 Y1,t,Y2,t 为例,下面简要介绍一下如何使用每种方法进行协整性的判断。
Engle-Granger Method 步骤
1.分别对 Y1,t 和 Y2,t 和它们的差分序列使用unit root test,来确定它们是否非平整。一般来说原始序列是非平整,但是各自的一次差分序列是平整的( Y1,t,Y2,t 为 I(1) )。 2.选取其中一个序列作为dependent variable、另一个为independent variable做linear regression(使用Ordinary Least Square), 例如
Y2,t=β0+β1Y1,t+ϵt
一般来说, Y1,t 和 Y2,t 应该存在较强的线性关系,使得 β1 的估计值statistically significant。 3.从linear regression结果中得到residual序列,对其使用unit root test测试平稳性(实际上就是测试 ϵt 是否是 I(0) )。如果得到的residual序列具有平稳性,说明 Y1,t,Y2,t 是协整的,存在长期的均衡关系。此时, β0,β1 分别协整均衡值和协整系数。
!!!穿插的有代码!!!!注意看!!!!代码很简单!!!!
单整序列
指数的对数收益率序列做了一次差分。实际我们可以在差分序列上再做差分。
当某一个不平稳的时间序列做了n次差分后第一次变成平稳序列了
那么我们就称这个时间序列为n阶单整。
根据重要统计量(之前介绍过的均值、方差、自相关系数)的可加性,我们有以下两个结论:
- 平稳序列的线性组合也是平稳的;
- 平稳序列和一阶单整序列的线性组合是一阶单整的;
协整关系
但是有一种情况我们可能用两个一阶单整的序列构造出平稳序列(平稳序列的一阶差分一定也是平稳的)。
对于两个走势很像的时间序列,比如,格力和美的的股价走势,它们的对数收益率序列可以看成股价序列的一阶差分。
对数收益率序列是平稳的。所以格力和美的的股价走势可以说是一阶单整的。
因为格力和美的的股价走势强相关,那么可以想象它们股价的差值序列似乎应该是平稳的。如果是平稳的,我们就说格力和美的的股价走势序列具有协整关系(Cointegration)。
协整关系通常用在配对交易中,用来判断两个走势相近的标的价格差值序列是否平稳,进而判断这两个标的走势是否平稳。
在实际应用中,我们通常会对标的价格取对数,以减小量纲的影响。
模型解释与协整检验
我们针对两个序列寻找它们的协整关系,我们在它们之间建立了下面的关系
由上式,我们已经假设这两个序列之间是线性关系。究竟具不具有线性关系,实际上需要验证的。所以当我们拟合出模型后,我们首先应该看看模型是否有不错的解释效果(实际上很多人都忽略了这一点);然后我们再进行协整的检验。
验证线性模型的解释效果有很多指标,SSE(和方差)、MSE(均方误差)、RMSE(均方根误差)、MAE(平均绝对误差)、R-Squared(R平方检验,为R平方,修正R平方等)
简单的恩格尔-格兰杰(Engel-Granger)检验法。对于下述关系式进行两步检验:
华泰柏瑞300与兴全300究竟能否搬砖?
p1 = get_price('510300.XSHG', start_date='2017-01-01', end_date='2019-12-13', frequency='daily', fields='close')
p2 = get_price('163407.XSHE', start_date='2017-01-01', end_date='2019-12-13', frequency='daily', fields='close')
ln_p1 = log(p1)
ln_p2 = log(p2)
import statsmodels.api as sm
x = ln_p2
y = ln_p1
# 所构建模型若含常数项使用这一步,不含常数项就不含这一句
X = sm.add_constant(x)
result = (sm.OLS(y,X)).fit()
打印拟合结果看看:
红色框体中的R平方分析是模型对原始数据的解释度。0.7左右说明模型的解释性马马虎虎。
绿色框体是我们求得的两个参数:α = 0.7082 ; β = 0.8818
按照这两个参数可以画出拟合的线性曲线(其实是直线):
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, y, 'o', label="data")
ax.plot(x, result.fittedvalues, 'r', label="OLS")
ax.legend(loc='best')
我们进一步用ADF检验看看其平稳性
from statsmodels.tsa.stattools import adfuller
adfuller(resid.close)
结果如下
(-1.5651429207395833,
0.5010757745369381,
5,
713,
{'1%': -3.43955476721974,
'5%': -2.865602155751202,
'10%': -2.5689331692727135},
-4994.155385095142)
t-检验值没有显著小于10%的临界值,说明不能拒绝不平稳的假设。
在statsmodels中有更方便的判断两者是否协整的函数。
from statsmodels.tsa.stattools import coint
coint(x, y)
(-1.4004315479475968,
0.7973652863497567,
array([-3.9117583774179283, -3.3446531236567063, -3.0503622399733086]))
可以看到程序自带的函数进行的协整结果的t-检验值(-1.4004315479475968)也没有显著地小于array
中的三个临界值,所以不能接受这两个序列平稳的结论。
我们看看残差序列
从残差序列也可以大概看出其不平稳性。
因此,利用华泰柏瑞300与兴全300搬砖的小伙伴可要小心,要反复确认它们在所考察的时间段内是否协整,且是否这种协整关系可延续。
另外,我们在建模的时候加入了常数项,也可以将常数项去掉看看建模效果。
我们从 rb 期货中选择两个品种进行分析,具体的品种根据相关性选择,后期会另外补充。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
a_price = pd.read_csv('./CloseA.csv')[:200]
b_price = pd.read_csv('./CloseB.csv')[:200]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(len(a_price)), a_price)
ax.plot(range(len(b_price)), b_price)
ax.legend(['a','b'])
plt.show()
从图中看,两个品种具有很强的相关性,并且都是不稳定的。
下面,我们通过ADF检验来看一下,两个序列是否是一阶单整的:
from statsmodels.tsa.stattools import adfuller
a_price = np.reshape(a_price.values, -1)
a_price_diff = np.diff(a_price)
b_price = np.reshape(b_price.values, -1)
b_price_diff = np.diff(b_price)
print(adfuller(a_price_diff))
print(adfuller(b_price_diff))
(-15.436034211511204, 2.90628134201655e-28, 0, 198, {'1%': -3.4638151713286316, '5%': -2.876250632135043, '10%': -2.574611347821651}, 1165.1556545612445)
(-14.259156751414892, 1.4365811614283181e-26, 0, 198, {'1%': -3.4638151713286316, '5%': -2.876250632135043, '10%': -2.574611347821651}, 1152.4222884399824)
从结果来看,两个序列都满足一阶单整,下面来判断两者是否存在协整关系。
statsmodels 模块中有 coint 函数可以用来检测协整关系,
它的内部实现就是基于 EG 协整检验的。
coint 函数如下:
from statsmodels.tsa.stattools import coint
print(coint(a_price, b_price))
(-3.9532731584015215, 0.008362293067615467, array([-3.95232129, -3.36700631, -3.06583125]))
从返回结果可以看出 t-statistic 值要小于1%的置信度,所以有99%的把握拒绝原假设,而且p-value的值也比较小,所以说存在协整关系。
低p值意味着高协整!
价差的计算
现在我们来计算两个序列的价差。为了计算它们的实际价差,我们首先要用线性回归来得到两个序列的回归系数。回归方程的常数项alpha就是我们需要的价差。也就是说,一只股票的价格减去另一只股票的价格乘回归系数beta,得到的才是它们的价差
相关性的另一个例子
残差序列
sed = S2 - b * S1或者,我们可以检查两个时间序列之间的比率
rio
无论我们是使用价差法还是比率法,(残差、比率)序列倾向于围绕均值移动。我们现在需要标准化这个比率,因为绝对比率可能不是分析这种趋势的最理想方式。为此,我们需要使用 z 分数。
z 分数是数据点与平均值的标准差数。更重要的是,高于或低于总体平均值的标准差的数量来自原始分数。z-score 的计算方法如下:
def zscr:
return (sres - ees.mean) / np.std
通过将另外两条线放置在 z 分数 1 和 -1 处,我们可以清楚地看到,在大多数情况下,与平均值的任何大背离最终都会收敛。这正是我们想要的配对交易策略。
价格比率的方法可能看起来比较刺激,它在实盘上往往是不可行的策略。我们还是应该选择用价差作为配对交易的选择标准。对协整的股票使用线性回归计算价差固然方便,但它在实盘上也不见得会有好的效果。其实还有很多其他计算价差的方法,这取决于你对处理协整序列的统计学方法有多了解
回到我们的例子,直接对股票数据进行价差计算在统计学上并不是很合适的手段。我们应该先进行标准化,比如使用熟悉的z-score法。但是我们需要注意,在写实盘策略时,假设我们的数据服从正态分布并不明智。金融数据常常是尖峰厚尾的分布,这意味着它们比正态分布更可能出现极端值
蓝色折线是标准化后的序列,黑色实线是它的平均值,上下两条橙色虚线代表平均值加减一倍标准差,即“阈值”
简单的配对交易策略:
• 当z-score低于1时做多;
• 当z-score低于1时做空;
• 当z-score趋近0时空仓
示意效果图
改进的领域和进一步的步骤
这绝不是一个完美的战略,我们战略的实施也不是最好的。但是,有几件事可以改进。
1. 使用更多的证券和更多样化的时间范围
对于配对交易策略的协整测试,我只使用了少数股票。自然地(并且在实践中)在行业内使用集群会更有效。我只用了只有5年的时间范围,这可能不能代表股市的波动。
2. 处理过拟合
任何与数据分析和训练模型相关的事情都与过拟合问题有很大关系。有许多不同的方法可以处理像验证这样的过拟合,例如卡尔曼滤波器和其他统计方法。
3. 调整交易信号
我们的交易算法没有考虑到相互重叠和交叉的股票价格。考虑到该代码仅根据其比率要求买入或卖出,它并未考虑实际上哪个股票更高或更低。
4. 更高级的方法
这只是算法对交易的冰山一角。这很简单,因为它只处理移动平均线和比率。如果您想使用更复杂的统计数据,请使用。其他复杂示例包括 Hurst 指数、半衰期均值回归和卡尔曼滤波器等主题。
构造SSD距离函数(累计收益率偏差)
## 构造SSD距离函数(累计收益率偏差)
import numpy as np
def SSD(priceX,priceY):
returnX = (priceX - priceX.shift(1)) / priceX.shift(1)[1:] # 计算 X 收益率
returnY = (priceY - priceY.shift(1)) / priceY.shift(1)[1:] # 计算 Y 收益率
# 这是将两个函数归一化的一个方法
# 也就是累计收益率的乘积
standardX = (returnX + 1).cumprod() # 累计乘
standardY = (returnY + 1).cumprod()
# 很明显这里求的是方差,用方差作为距离
# 结合上面的资料,方差作为距离在实际中可能有问题
SSD = np.sum((standardX - standardY) ** 2) # 计算累计收益率偏差
return(SSD)
# 求中国银行和浦发银行价格距离
dis = SSD(P_zhonghang_f,P_pufa_f)
dis
0.47481704588389073
将上证50板块的50只股票两两配对(共计1225对)
形成期(Formation Period)为245天
以此类推,可以计算出1225个SSD值
将这些值由小到大进行排序
然后从中选出前5组作为配对交易策略的5个股票对
lst = list(sh_form.columns)
d = dict()
for i in range(len(lst)):
for j in range(i+1,len(lst)):
P_zhonghang_f = sh_form[lst[i]]
P_pufa_f = sh_form[lst[j]]
dis = SSD(P_zhonghang_f,P_pufa_f)
d[lst[i]+'-'+lst[j]] = dis
# 按照‘值’排序,并挑出前5个最小距离股票对
d_sort = sorted(d.items(),key=lambda x:x[1])
d_sort[:5]
[('600015-601166', 0.24566159437495438),
('601288-601398', 0.246846282979896),
('600050-601288', 0.27890721330378976),
('601166-601288', 0.2920160356208131),
('601398-601857', 0.3299872459845748)]
用形成期(一年)的数据在板块的成分股中选股票
运用最小距离法可以挑选出股票对
计算形成期(Formation Period)内标准化的价格序列差
的平均值 μ和标准差 σ 。
然后,选定交易期(Trading Period )进行交易。
Gatev等学者运用最小距离法选出股票对
设定交易信号触发点为 μ ± 2 σ
交易期的适用期限为6个月
当交易期超过6个月以后
重新设定形成期和选取股票对
由于浦发银行与中国银行同为银行业股票
且银行业股票股价比较稳定
因此我们设定交易期内价差超过 μ + 1.2
或者 μ − 1.2 σ将触发交易信号进行交易。
当交易期的标准化价差又回复到均值 μ附近时,反向操作平仓,从而赚取价差收益。
#图形输出中文等一些的的参考代码
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
import matplotlib
matplotlib.rcParams['axes.unicode_minus']=False # 负号显示问题
plt.figure(figsize=(10,4))
ax = plt.subplot()
#ax.plot(return_zhonghang, label='中国银行')
#ax.plot(return_pufa, label='浦发银行')
plt.title('图2 中国银行 vs 浦发银行(收益率)',fontsize=15)
ax.set_xlabel('日期', fontsize=14)
ax.set_ylabel('收益率', fontsize=14)
ax.legend()
plt.show()
在形成期中计算浦发银行与中国银行股票标准化价格序列差 SSD-pair
并求出价差的平均值 meanSSD-pair
和标准差 sdSSD-pair
# 标准化价格(归一化处理)
standard_zhonghang = (1 + return_zhonghang).cumprod()
standard_pufa = (1 + return_pufa).cumprod()
# 求中国银行A与浦发银行B标准化价格序列的价差
SSD_pair = standard_pufa - standard_zhonghang
#计算形成期标准化价格差序列的均值和方差
meanSSD_pair = np.mean(SSD_pair)
sdSSD_pair = np.std(SSD_pair)
###上面只是理论示意,实际不会这样去做,参考前面的文章,但还请将示意看完
#设置交易期交易信号触发点:mu +- 1.2sigma
thresholdUp = meanSSD_pair + 1.2 * sdSSD_pair
thresholdDown = meanSSD_pair - 1.2 * sdSSD_pair
设定交易期(Trading Period )时间
选取交易期数据,寻找配对交易开仓和平仓位点
当价差上穿 μ + 1.2 σ ,反向开仓
当价差线回复到均线附近(可以给出阈值进行度量)时,进行平仓
当价差线下穿 μ − 1.2 σ线时正向开仓
当价差线再次回复到均线附近时平仓。
tradStart = '2015-01-01'
tradEnd = '2015-06-30'
P_zhonghang_t = sh.loc[tradStart:tradEnd, '601988']
P_pufa_t = sh.loc[tradStart:tradEnd, '600000']
# 定义价差函数
def spreadCal(x,y):
retx = (x-x.shift(1)) / x.shift(1)[1:]
rety = (y-y.shift(1)) / y.shift(1)[1:]
standardX = (1+retx).cumprod()
standardY = (1+rety).cumprod()
spread = standardX-standardY
return(spread)
# 计算归一化以后的价差
TradSpread = spreadCal(P_pufa_t,P_zhonghang_t).dropna()
# 可视化
plt.figure(figsize=(12,6))
TradSpread.plot()
plt.title('图5 中国银行与浦发银行股票价差序列(交易期)',loc='center',fontsize=16)
plt.axhline(y=meanSSD_pair, color='black')
plt.axhline(y=thresholdUp, color='green')
plt.axhline(y=thresholdDown, color='green')
plt.show()
结论:如图5所示
价差序列多在1.2倍标准差范围内
从2015年1月1日至2015年6月30日
价差序列向上突破1.2倍标准差线3次
向下突破1.2倍标准差线3次
共有6次开仓机会
且价差序列比较稳定,开仓后均有平仓机会。
注:平仓
(1)均值附近平仓的度量:μ ± 0.2 σ
(2)控制风险平仓的度量:μ ± 2.0 σ
我的结论:
线性回归
不管是是拿两个序列直接构造
还是用他们的对数值构造
求得的距离(归一后直接减,还是欧拉距离)
还是残值序列
或者是比率序列
三种都应该在各自的均值附近正泰分布
但考虑到正态分布的左边右偏
还是应该使用zscore以及相关系数进行纠正
也就是说,应该用 zscore*相关系数,作为触发点.