欢迎光临散文网 会员登陆 & 注册

量化交易软件:经验模态分解法介绍

2023-07-28 14:13 作者:bili_45793681098  | 我要投稿

简介

赫兹量化在实践中必须处理的所有真实过程都很复杂,作为一项原则,包含大量的分量。例如天气。在分析降水图时,我们应记住,它们表示各种各样的过程的互动,例如季节变换、全球变暖/变冷过程、洋流变化、气旋和反气旋的动态、排放到大气中的二氧化碳的量、太阳活动周期等,内容不胜枚举。

因此很难分析此类图,因为其分量在相互作用时会遮挡我们要识别的规律或让规律扭曲。这样会让人有理由出现将考虑的过程分解为单个分量并单独分析每个分量的想法。分析单个分量并研究它们已经为当前过程做出的贡献有助于我们更好地了解正在进行的过程,并提高预测可靠性。

在讨论有关交易的各种信息时也不例外,包括依据大量不同因素形成的货币报价。这是很自然地期待预先分解为单个分量能够大大促进它们的进一步分析的原因。

术语“分解”在形式上指将一个复合过程或复合材料分解为单独的组成部分。但是在与不同过程分析、信号分析、各种序列分析有关的很多领域中,此术语长期以来具有更为广阔的含义,通常不是指分解为实际的初始组成部分,而是指分解为在形成初始数据时实际上并不存在的某些函数。这些函数是在数据分解过程中人工形成的,但是尽管它们是“人工”的,它们也能更加深入地分析数据,有助于识别隐藏的形态。

在市场分析中使用的大量方法或明或暗都可归于从分析过程中挑选某些分量的方法,即分解法。让赫兹量化简要地回顾一下这些方法。


1. 分解

在实践中,有很多各种各样的分解法可应用到考虑的给定序列。这些方法可能有不同的基本数学或经验方法,不同的复杂程度和不同的应用领域。

例如,即使一个基本市场分析在一定程度上也可被视为一种分解法。此分析处理一组直接影响市场状况的初始事件产生的影响。换言之,所分析的市场过程被暗中分解为若干组成该过程的事件。

以后将不触及与基本分析有关的问题。赫兹量化假定有关过程的任何进一步的信息都不可用;我们拥有的仅是表示给定过程的行为的一个序列。

可以用常见的方法将一个序列分解为几个组成部分,以之说明最简单的分解例子。例如,赫兹量化为任意货币对在图表上标绘移动平均线 (MA)。然后从初始序列中减去生成的曲线。这样一来,我们将得到初始序列的两个组成部分,MA 曲线和残数。相同的步骤,仅使用较长周期的移动平均线,在应用到获得的残数时,将产生三个组成部分 - 两条 MA 曲线和变换的残数。如您所见,可以使用任何可用的方式安排分解过程。要点在于此类过程的结果的属性。

在著名的分解和频谱分析方法中,傅里叶变换特别值得在这里提及。傅里叶变换属于使用固定谐波基函数的正交变换类。傅里叶变换结果可表示为初始过程分解为具有固定频率和幅度的谐函数。注意,有两点对我们特别重要。

第一点,变换始终依据一个固定的、预先设定的正交函数基进行。即变换基不取决于所变换的序列的性质。

第二点,生成的谐分量的幅度和频率值是恒定的。即它们的值在整个初始序列中都保持不变。这意味着如果给定初始序列的性质在所考虑的区间内出现变化,则这种变化将不会在变换结果中反映出来。在此情况下,获得的结果将仅反映过程的某个平均状态,因为此变换依据初始数据的静态假设。

为了避免与初始序列的非静态性有关的约束,赫兹量化可以将傅里叶变换转换为小波变换。小波变换,与傅里叶变换类似,以固定的函数基进行分解。与傅里叶变换不同,此基是预设的,即应选择在变换中使用的小波。

此外,与傅里叶变换相比,从小波变换生成的每一个分量都有确定其随时间而变换的比例和水平的参数,这样解决了与所分析的过程可能具有的非静态性有关的问题。

傅里叶变换和小波变换都被广泛认可,因为使用充分建立的数学技能和可用的有效实施算法。此外,两种变换都似乎特别通用,能够成功应用于不同的领域。

但是出于实践目的,最好使用不仅能够处理非静态过程,还能使用按初始数据确定的自适应变换基的变换。此类变换确实存在,以下将对其进行简要介绍,从而说明本文的主题。


2. 经验模态分解

经验模态分解 (EMD) 作为 希尔伯特-黄变换 (HHT) 的基础部分被提出来。可以这么说,希尔伯特-黄变换分为两个阶段进行。首先,使用 EMD 算法获得本质模态函数 (IMF)。

接着,在第二阶段,通过对上一步获得的结果应用希尔伯特-黄变换得到初始序列的瞬时频率谱。HHT 能够获得非线性和非静态序列的瞬时频率谱。之后,可以使用经验模态分解处理这些序列。

然而,本文将不介绍使用希尔伯特变换标绘瞬时频率谱。赫兹量化将仅着重于 EMD 算法。

与前面提及的傅里叶变换和小波变换相比,EMD 将任何给定数据分解为本质模态函数 (IMF),这些函数在分析上未被设定,而是由所分析的序列单独确定。在这种情况下,基函数从输入数据自适应地直接得出。从 EMD 生成的 IMF 应满足以下要求:

  1. IMF 极值的数量(最大值和最小值的数量之和)与零穿越的数量必须相等或最多相差 1;

  2. 在 IMF 的任意点,局部最大值定义的包络线的平均值和局部最小值定义的包络线的平均值应等于零。

分解生成一系列的频率分阶 IMF 分量。每个后面的 IMF 包含比前面的 IMF 更小的频率振荡。尽管“频率”这一术语在运用到 IMF 时并不十分正确,但它可能最适合用于定义 IMF 的性质。本质在于尽管 IMF 是振荡性质,但其幅度和频率可以沿时间轴变化。

单独依据描述对 EMD 算法执行结果进行可视化非常困难,因此让我们继续其软件实施,这样让我们有机会了解算法的特点。


3. EMD 算法

黄锷 (Norden E. Huang)提出的算法以产生序列的局部最大值和最小值所定义的平滑包络线,接着从初始序列减去这些包络线的平均值为基础。这要求识别所有局部极值,然后用三次样条曲线进一步将这些极值连接起来,以生成上下包络线。

标绘包络线的过程如图 1 所示:



编辑


图 1. 描绘包络线和它们的平均值


图 1 用细蓝线给出了所分析的序列。分别用红色和蓝色表示序列的最大值和最小值。用绿色给出包络线。

依据两条包络线计算平均值,并在图 1 中以虚线表示。从初始序列中进一步减去这样计算出来的平均值。

以上步骤生成所需经验函数的首次逼近提取。为了获得最终的 IMF,应再次识别新的最大值和最小值并重复以上所有步骤。此次重复的过程称为筛选。重复筛选过程,直到满足某个给定的停止标准。筛选停止标准的选择是影响最终分解结果的要点之一。我们将在迟些时候讨论这个问题。

如果成功完成筛选过程,则我们将获得第一个 IMF。可以通过从原始信号减去先前提取的 IMF,再一次重复上述过程而获得下一 IMF。这样一直继续到提取完所有 IMF 为止。筛选过程通常在残数只包含不超过两个极值时停止。

可以看到,描述的经验模态分解过程并不是基于严格的数学计算,但是真正基于经验,正如其名。尽管黄锷提出的以上算法简单明了,仍然有几点可被视为其弱点。

有关此主题的不同文章提供了对其弱点的详细说明,以及对黄锷的算法进行现代改进的方式。本文将不着重于对此方法进行的可能现代改进,但是将简单地说明创建其软件实施的尝试。以下简单地介绍实施的特征。


4. CEMDecomp 类

实施 EMD 算法的 CEMDecomp 类是依据研究希尔伯特-黄变换和经验模态分解的互联网文章创建的。实施的算法在本质上与黄锷最初提出的算法非常类似,没有包含任何重大修改。

以下是源代码的一个片断,可以在本文末尾的 CEMDecomp.mqh 文件中找到。

//------------------------------------------------------------------------------------ // The Empirical Mode Decomposition (EMD). //------------------------------------------------------------------------------------ class CEMDecomp:public CObject  { public:  int     N;                 // Input and output data size  double  Mean;              // Mean of input data  int     nIMF;              // IMF counter  int     MaxIMF;            // Maximum number of IMF  int     MaxIter;           // Maximum number of iterations  int     FixedIter;         // 0-variable number of sifting iterations;                             // 1-always ten sifting iterations.  double  IMFResult[];       // Result private:  double  X[];  double  Imf[];  double  XMax[];            // x of local maxima  double  YMax[];            // y of local maxima  double  XMin[];            // x of local minima  double  YMin[];            // y of local minima  double  EnvUpp[];          // Upper envelope  double  EnvLow[];          // Lower envelope  double  Eps;               // Accuracy comparison of floating-point numbers  double  Tol;               // Accuracy of calculation IMF public:    void    CEMDecomp(void);  int     Decomp(double &y[]);          // Decomposition  void    GetIMF(double &x[], int nn);  // Get IMF number nn private:  int     arrayprepare(void);  void    extrema(double &y[],int &nmax,double &xmax[],double &ymax[], int &nmin,double &xmin[],double &ymin[]);  int     SplineInterp(double &x[],double &y[],int n,double &x2[], double &y2[],int btype=0);  };

让我们看一看在 CEMDecomp 类中声明的公共变量和方法。

N 是序列中元素的数量。变量 N 的值在调用 Decomp() 方法之后生成,等于输入序列的长度。提取的 IMF 将具有相同的大小。

Mean 是输入序列的平均值。值在调用 Decomp() 方法之后生成。

nIMF 是 IMF 计数器。在调用 Decomp() 之后,它包含提取的 IMF 的数量加 2。因此,这个值指出使用 GetIMF() 方法可以读取多少分量。这就是说,索引为 0 的分量将始终包含从中减去其平均值的初始序列,索引为 nIMF 的分量将包含分解的残数。

MaxIMF 是 IMF 的最大允许数量。当 IMF 的数量达到 MaxIMF 值时,输入序列分解为单个的 IMF 将停止。此变量的值可在调用 Decomp() 方法之前设置。默认值为 16。

MaxIter 是在筛选过程中允许的最大迭代次数。如果筛选过程的迭代次数达到此值,则不管是否获得需要的精确度,筛选都会停止。此变量的值可在调用 Decomp() 方法之前设置。默认值为 2000。

FixedIter 是一个标记,在筛选中设置一个停止标准。如果 FixedIter 的值为零,则在达到给定精确度时,每个 IMF 的筛选过程就会停止。对不同 IMF 的提取而言,实现给定精确度所需的迭代次数可能有所不同。如果 FixedIter 设置为 1,则 IMF 会在 10 次迭代内被提取出来。此变量的值可在调用 Decomp() 方法之前设置。默认值为 0。

Decomp(double &y[]) 是主要的类方法,执行分解。它以输入参数的形式接收到一个包含输入数据的数组的引用 。在成功完成时,变量 N 将等于输入数组的长度。提取的 IMF 将具有相同的大小。变量 Mean 将等于输入序列的平均值,变量 nIMF 将等于可用 GetIMF() 方法读取的分量的数量。

GetIMF(double &x[], int nn) 用于确保访问用 Decomp() 方法获得的结果。用 nn 设定数量的分量,这些分量会被复制到数组,而数组的地址会作为一个输入参数传递。这就是说,索引为 0 的分量将始终包含从中减去其平均值的初始序列,索引为 nIMF 的分量将包含分解的残数。如果作为参数传递的数组长度小于生成的分量的长度,则会按数组长度允许的情况填充数组。

可以用以下例子来说明 CEMDecomp 类的使用:

#include "CEMDecomp.mqh" //------------------------------------------------------------------------------------ // Script program start function //------------------------------------------------------------------------------------ void OnStart()  {  int n,ret;  double yy[],imf2[];    n=400;                                    // Input sequence length  ArrayResize(yy,n);                         // Array of input data  ArrayResize(imf2,n);                       // Array for reading the results    CopyOpen(_Symbol,PERIOD_CURRENT,0,n,yy);      // Generation of input data    CEMDecomp *emd=new CEMDecomp();           // Creation of the CEMDecomp class instance  ret=emd.Decomp(yy);                       // Decomposition of the input sequence    if((ret==0)&&(emd.nIMF>3))                // If there is no error and the sufficient                                            // number of components was extracted,    emd.GetIMF(imf2,2);                     // copy component number 2 into                                            // array imf2[].  delete(emd);                              // Deletion of the CEMDecomp class instance    // One of the extracted components in array imf2[].  } //------------------------------------------------------------------------------------

可以在本文末尾的 CEMDecomposition.zip 压缩文件中找到通过 Web 界面显示提取的 IMF 的完整分解例子。为了运行这个例子,应解压缩指定的压缩文件,并将整个 \CEMDecomposition 目录及其内容放在客户端的 \Indicators 或 \Scripts 目录内。之后,您可以编译并运行 EMDecomp_Test.mq5 脚本。请记住,应允许在客户端中使用外部库。

图 2 显示另一个例子,使用 USDJPY 每日报价的分解,序列长度为 100 个元素。可以看到,此序列的分解生成四个 IMF 提取和残数。




量化交易软件:经验模态分解法介绍的评论 (共 条)

分享到微博请遵守国家法律