量化投资学习笔记104——股价预测2:集合经验模态分解方法(EEMD)

EEMD方法我也是第一次听说,看论文吧。
EEMD是在EMD的基础上发展起来的,所以先看看EMD的 原始论文。作者应该是位华人。
N. E. Huang et al., “The empirical mode decomposition and the Hilbert spectrum for non-linear and non stationary time series analysis”, Proc. Royal Soc. London A, Vol. 454, pp. 903-995, 1998.
EEMD是一种分析非线性不稳定数据的新方法。它可以将任何复杂数据分解为有限的,通常数量很少的“内在模式函数”(intrinsic mode functions,IMF,有的文献叫本征模态函数),分解方法是自适应的,高效的。结果是一个能量-频率-时间分布。该方法的关键是引入了基于信号局部特征的“内在模式函数”,它使得瞬时频率有意义。而复杂数据的瞬时频率的引入,消除了对非线性和非稳定数据的谐波(spurious harmonics)的需要。
傅里叶分析有其局限:系统必须是线性的,数据必须是严格周期性的或稳定的,否则,傅里叶分析的结果可能缺乏物理意义。稳定性是很多数据分析方法的要求。我们面对的数据很少能满足稳定性和线性的要求,但我们常常盲目的使用傅里叶分析。这常导致能量扩散。
经验模式分解(empirical mode decomposition,EMD)方法,生成一些内在模式函数(IMF),并计算瞬时频率。由此,可以在频率和时间轴上确定任何事件。最重要的是,它是自适应的。
传统的非稳定数据的方法:①频谱图(spectrogram)。是有限时间窗口宽度的傅里叶分析。②小波分析(The wavelet analysis),使用可调时间窗口进行傅里叶分析。其问题是一旦确定了基波就要用其去分析所有数据。③维格纳准概率分布(Wigner–Ville distribution),它是中心协方差函数(central covariance function)的傅里叶分析。使用时需要进行很多调整。④蜕变频谱(Evolutionary spectrum),将传统的傅里叶分析从正弦余弦函数扩展到一族正交函数。其难点是找到基函数的定义。⑤经验正交函数展开(The empirical orthogonal function expansion,EOF)。⑥其它方法。
处理非线性不稳定数据的方法的要求:完整、正交、局部、自适应。
EMD方法分两步,首先对数据进行处理将其分解为IMF,接着对这些分解了的IMF运用希尔伯特变换,生成能量-频率-时间分布。瞬时频率只在数据的一定范围内可以定义(超出范围它就不恒定了),这也为分解数据提供了方法。方法是找局部零点。具体来说IMF需满足两个条件:①在整个数据中,极值点和穿越0点(extrema and …… zero crossings)的数量必须相等或最多相差1。②在任何点,由局部最大值定义的包络线和由局部最小值定义的包络线的平均值为0。
对数据的分解基于下述假设:①数据至少有两个极值——一个极大值和一个极小值。②时间区间在极值之间定义。③如果数据缺乏极值但有波动变化,可以进行一次或多次微分来获得极值。
具体方法:用原始数据减去最大值包络线与最小值包络线的平均值,得到的结果作为新的数据再去减包络线的均值,如此迭代,直到结果符合IMF的条件。可以通过计算相继两次迭代结果的标准差来判断迭代停止的条件。然后对每个IMF运用希尔伯特变换,计算瞬时频率。
具体计算过程,验证过程,与传统的小波变换等方法比较等内容略过了。来看应用。在看论文的应用部分之前,找到一个python有现成的库的:pyemd,先照着文档试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from PyEMD import EMD
import numpy as np
import matplotlib.pyplot as plt


def testPyEMD():
s = np.random.random(100)
emd = EMD()
IMFs = emd.emd(s)
print(len(IMFs), len(IMFs[0]), type(IMFs))
fig = plt.figure()
ax = fig.add_subplot(len(IMFs)+1, 1, 1)
ax.plot(s)
for i in range(len(IMFs)):
ax = fig.add_subplot(len(IMFs)+1, 1, i+2)
ax.plot(IMFs[i])
plt.savefig("./output/emd.png")
plt.close()


自己动手做就比较清楚一些了。就是找原始数据的局部最大值和最小值,连接形成包络线,两个包络线之间的均值形成新的数据,再进行上述过程,直到无法再进行(没有两个或以上的极值点形成包络线)时,形成的就是所谓的内部特征函数(IMF)。整个过程中会形成不同的对原始数据的分解。
再试一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 例子2
t = np.linspace(0, 1, 200)
s = np.cos(11*2*np.pi*t*t) + 6*t*t

IMF = EMD().emd(s, t)
N = IMF.shape[0] + 1

# 画结果
plt.subplot(N, 1, 1)
plt.plot(t, s, 'r')
plt.title("Input signal: $S(t)=cos(22\pi t^2) + 6t^2$")
plt.xlabel("Time [s]")

for n, imf in enumerate(IMF):
plt.subplot(N, 1, n+2)
plt.plot(t, imf, 'g')
plt.title("IMF "+str(n+1))
plt.xlabel("Time [s]")

plt.tight_layout()
plt.savefig("./output/emd2.png")
plt.close()


至于这些分解具体怎么运用,再去看看原论文吧。
其应用主要分两类,一类是对微分方程等求数值解,其与传统方法相比优势是物理意义更明确。这部分略去。另一类是处理实验和观测数据,进行时间序列数据分析。但是作者举的那些应用的例子,分析机械振动,地震数据等,我都看不太懂。先看讨论吧。
作者认为该方法是分析非线性不稳定数据的强有力的方法,其优势在于分解的结果具有物理意义。需要改进的地方在于计算包络线的插值方法,作者使用的三次条样插值(cubic spline fitting)能适用于大部分情况,但还是有问题,比如太耗时,需要有更好的拟合方法。其次需要改进末端效应(end effects)。主要在拟合以及希尔伯特变换时。第三,要注意在强信号中包含弱信号的情况。第四,需要对数据进行过采样以获得精确的瞬时频率。第五,如果频率过于接近,则该方法无法对其进行分解。第六,该方法并不保证分解结果有物理意义。
再接着把EEMD的原始论文看一下吧。
参考PyEMD文档里作者的一段话:“I, the PyEMD’s author, will go even a bit further. If one needs such large resolution then the EMD is not suitable for them. The EMD is not robust. Hundreds of iterations make any small difference to be emphasised and potentially leading to a significant change in final decomposition. This is the reason for creating EEMD and CEEMDAN which add small perturbation in a hope that the ensemble provides a robust solution”。意思是EMD并不健壮,进行数百次迭代后,小的改变会导致结果的很大不同。因此才产生了EEMD和CEEMDAN等改进。
EEMD的原始论文: Z. Wu and N. E. Huang, “Ensemble empirical mode decomposition: A noise-assisted data analysis method”, Advances in Adaptive Data Analysis, Vol. 1, No. 1 (2009) 1-41.
总体经验模式分解算法(Ensemble Empirical Mode Decomposition ,EEMD)是一种噪音辅助数据分析(noise assisted data analysis,NADA)技术。EMD的最大问题是频率特征的模式混合(frequent appearance of mode mixing)。模式混合的原因是信号间歇(signal intermittency)。这不仅会导致严重的时间-频率分布混淆,还会使IMF的物理意义丧失。EMMD将真实的IMF视为样本的均值,每个样本为信号加上一个有限振幅的白噪声。经过这个总和过程,可以自然的将数据区分而不用主观选择。
EEMD的原则:增加的白噪声是对整个时间-频率空间的抽样,当信号被加入白噪声背景后,不同尺度的频率模式就自然显现在白噪声背景建立的参照系里了。对于足够多的样本,噪声的影响会互相抵消。样本均值即被视为是真实结果。随着样本量的增加,剩下的就是信号本身。
再用PyEMD试一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# eemd
def testEEMD():
t = np.linspace(0, 1, 200)
# 定义信号
sin = lambda x, p: np.sin(2*np.pi*x*t + p)
S = 3*sin(18,0.2)*(t-0.2)**2
S += 5*sin(11,2.7)
S += 3*sin(14,1.6)
S += 1*np.sin(4*2*np.pi*(t-0.8)**2)
S += t**2.1 -t


eemd = EEMD()

# 设置探测极值的方法
emd = eemd.EMD
emd.extrema_detection="parabol"

# 对信号执行eemd
eIMFs = eemd.eemd(S, t)
nIMFs = eIMFs.shape[0]

# 画结果
plt.figure(figsize=(12,9))
plt.subplot(nIMFs+1, 1, 1)
plt.plot(t, S, 'r')


for n in range(nIMFs):
plt.subplot(nIMFs+1, 1, n+2)
plt.plot(t, eIMFs[n], 'g')
plt.ylabel("eIMF %i" %(n+1))
plt.locator_params(axis='y', nbins=5)


plt.xlabel("Time [s]")
plt.tight_layout()
plt.savefig('./output/eemd.png', dpi=120)
plt.close()


现在,基本会用了,但是具体怎么运用,尤其是在金融领域呢?找了一篇硕士论文看看。
蒋国均.我国沪深股票市场价格指数相关性分析及预测研究 ——基于EMD分解技术的应用.暨南大学硕士学位论文(2014).
作者将沪市、深市指数进行EMD分解,然后根据不同分量的周期、均值、方差等特征进行构建组合,提取出市场波动项,重大事件影响项和长期趋势项三个时间序列,并对三个时间序列分别构建SVM模型进行预测,得到各序列预测值,最后将各预测值进行组合得到最终预测结果。结果发现这样预测精度更高。
我就按作者的方法,预测一下沪深300指数吧。先下载数据,下载2005年1月1日到2020年12月31日的数据,其中2019年到2020年的数据作为测试数据,之前的数据作为训练数据。
画一个训练数据

下面对数据进行EEMD分解。
加入100组标准差为0.2的白噪音。

1
2
3
4
5
6
7
eemd = EEMD(trials=100, noise_width=0.2)
eIMFs = eemd.eemd(train_data.values)
plt.figure()
visual = Visualisation()
visual.plot_imfs(eIMFs, include_residue=False)
plt.savefig("./output/eemd_hs300.png")
plt.close()

分解结果

分解为11个IMFs,与论文里类似。
然后计算每个IMF的周期,均值,方差,方差占比,pearson相关系数等统计指标。数据与原始总体数据的相关性。
其中周期用IMF数据个数除以IMF极值点个数来表示,方差占比用IMF数据方差除以原始总体数据方差来表示,pearson 相关系数则度量了IMF数据与原始总体数据的相关性。
计算结果如下:

从第6个IMF开始,方差占比增大,波动周期变长,和原始数据的相关系数也增大。
把第0到5六个IMFs相加作为高频部分,代表市场的正常波动项,6-11项相加作为低频项,代表非金融市场正常波动项,即外部环境重大事件,剩余分量代表市场长期趋势。(这一项前面漏了,加上)。

有个问题:剩余分量趋势是向下的,市场长期趋势向下?另外跟文章中的分量趋势也不太一样。
下面就进行预测了。作者的方法是分别对三个分项用支持向量机SVM进行预测,再把结果进行组合。但是没说怎么组合,就直接相加吧。
再找ta的参考文献看看。
陶小龙.基于支持向量机的股市预测.北京理工大学理学硕士学位论文(2005).
先按照文章进行支持向量机预测。
传统金融时间序列有两种研究方法,一种是从基本的经济原理出发建立金融时间序列服从的数学模型,如Markovitz的投资组合理论,资本资产定价模型(CAPM)、套利定价理论(APT)、期权定价模型等,但现实不一定符合其假设。因此实际效果并不理想。另一种是从统计角度进行研究,缺乏理论性,但实际应用中效果较好。统计方法还可以对经济模型的好坏进行检验和评价。
股市预测一般基于三点假设:①有效市场理论;②供求决定假设;③历史相似原则。
技术分析依赖图表和主观判断,严重依靠经验,可靠性受到质疑。
用智齿向量回归机进行预测的步骤:
①试验规模的选取,决定训练集的数量、试检测集数量,以及两者的比例。
②预测参数的选取,包括参数系统的形式,参数的内容。
③标准化形式的选择。
④核函数形式的选择。
⑤核函数参数的选择。
另一篇
金得宝.基于支持向量机的股市预测研究.浙江大学硕士学位论文(2010).

输入特征向量为开盘价、最高价、最低价、成交量、收盘价、5天/10天/20天指数移动平均。输出为下一日收盘价。用正则均方误差(NMSE)、平均绝对误差(MAE)、方向对称性指标(DS)作为评价标准。前两者越小越好,DS越大表示其预测曲线与实际曲线方向趋势上拟合的越好。核函数参数选择:C一般[10,100],太小欠拟合,且SV数量随C增加而下降,C太大过拟合,泛化能力下降,相应的训练时间过长。ε = 0.001, ζ = 0.001。

两篇论文,一篇没具体代码,一篇代码是matlab。还是直接搜吧。
参考这篇
先用普通SVM实现一下。用分类算法,数据与前文多元线性回归一致。

准确率85.7%。
下面用这个训练好的模型按照上次的回测程序回测一下看看。
年化收益率:1.489342
最大回撤 夏普比率 索提比率 α β
-0.013315 4.266112 49.991836 -0.85213 0.471451
还不错,但是比多元线性回归的差一些。现在把EEMD加上。将七个特征分别进行EMMD分解,除了最低价分解为6项外,其余特征都分解为7项。像这样的:

将前3项作为高频项,其余的作为低频项,再加上剩余项。每个特征都分解为三个特征。
合并以后是这个样子。

现在就用这些处理后的特征数据进行训练支持向量机模型,结果,预测准确率反而更低了。
预测准确率: 0.7959183673469388
回测一把看看。
在回测这里卡了几天,始终没调通。后来我突然想通了,在对特征进行eemd分解的时候,我是把所有数据一起分解,然后再划分训练数据和测试数据。这样测试的时候相当于是用了未来数据的。在真正用的时候,是用今天的数据预测明天的收盘价,只有一组特征,喂给模型结果eemd分解那里报错。应该是不能只用一个数据来作为输入。这种方法尝试就到这里吧,不知道我参考的那些论文有没有这个问题的。
尝试虽然失败了,但是知道了有EEMD这种方法,将股价数据分解成高频,低频部分,低频部分看着跟股价的中期趋势比较一致,虽然可能没法拿来直接预测第二天的股价,但是拿来判断股价是不是到顶/底了行不行?开发策略时可以用用看。
没调通的代码
接下来再试试其它的预测方法。

我发文章的三个地方,欢迎大家在朋友圈等地方分享,欢迎点“在看”。
我的个人博客地址:https://zwdnet.github.io
我的知乎文章地址: https://www.zhihu.com/people/zhao-you-min/posts
我的微信个人订阅号:赵瑜敏的口腔医学学习园地

欢迎打赏!感谢支持!