本文的目的是强调自然变换的水平组合的概念。我们在上一篇文章中探讨了它的反义词,我们在文章中看到了如何在两个类别之间检索三个函子,这意味着当类别是价格时间序列和相同价格的移动平均时间序列这样简单的数据集时,可以推断出垂直组合中的两个自然变换。在这篇文章中,我们通过添加移动平均的第三类移动平均,即双重指数移动平均,来水平扩展移动平均时间序列。我们对这一著名指标的变体并没有真正使用既定的公式,而是出于我们的目的,它只是通过成为移动平均的移动平均来平滑移动平均线。函子关系与我们在上一篇文章中的类似,但我们在类别之间只有两个函子,而不是上一篇中的三个。然而,与上一篇文章一样,任何两个类别之间的每个函子都有自己的移动平均周期,因此每个函子对之间的自然变换可以帮助我们形成时间序列缓冲区进行分析。
预测交易波动性的重要性可能不如首先确定一个人应该持有的头寸类型(无论是多头还是空头)那么关键。尽管如此,它确实为我们提供了一个机会,来研究其他现有进场信号策略的任何潜在用途和改进,甚至是利用其思想创建新策略。这是我们在过去的文章中探讨过的,所以在这里重新回顾并不陌生。我们将把我们的波动率预测与内置的动量振荡指标(AO)信号类配对,波动率预测将在EA跟踪类的例子中处理。一如既往,欢迎读者用其他信号或他们自己的私人策略来测试这门课,以找出最适合他们的;就本文而言,我们将坚持使用动量振荡指标
预测波动性
因此,预测波动性就是我们的专家跟踪类实例正在做的事情,就像本系列中的几篇文章中的情况一样。我们在这里使用过滤器进行此操作;移动平均趋势需要通过自然转换缓冲之间的显著相关性来确认。但我们本可以采取的另一种更倾向于波动性的方法是将范畴1作为一系列价格区间(高点减去低点)。这个系列的平均值将在第2范畴中,第3类将是它的DEMA,就像我们在所附代码中对收盘价所做的那样。这个过程基本相同,但这种方法可以产生更协调和更敏感的波动结果。
MQL5中的实际实现
为该模型设置MQL5环境将与我们在本系列中看到的非常相似。再次,专家跟踪类的实例作为MQL5向导中专家顾问的一部分进行组装,为了使其工作或进行测试,我们需要在向导中首先选择专家信号类的实例。在这篇文章中,使用了内置的动量振荡指标信号类。这里的“内置”是指IDE中提供的信号库中已经存在的内容。
我们在这里不一定要为函子编写代码,因为我们可以使用移动平均类的内置实例。“CiMA”和“CiDEMA”类可以轻松处理我们的移动平均和双重指数移动平均需求。尽管如此,我们还是声明并使用'CObjects'类的实例来处理这些平均值,它们的声明如下:
...
CObjects<double> m_o_average_a;
CObjects<double> m_o_average_b;
CObjects<double> m_o_average_c;
CObjects<double> m_o_average_d;
...
与上一篇文章一样,我们需要初始化自然变换缓冲区,因为读取信号的能力从一开始就很重要。它们的大小和以前一样是一个输入参数“m_transforms”,就像上一篇文章中的情况一样,因此这一重要步骤的处理方式与我们在上一篇中实现的方式几乎相同,主要区别是我们有4个移动平均实例用于缓冲区。刷新这些值也有点类似于初始化,按照下面的列表进行处理:
//+------------------------------------------------------------------+
//| Refresh function from Natural Transformations. |
//+------------------------------------------------------------------+
void CTrailingCT::Refresh(void)
{
if(!m_init)
{
Init();
}
else
{
m_close.Refresh(-1);
int _x=StartIndex();
for(int i=m_functor_ab+m_functor_ab-1;i>0;i--)
{
m_e_price.Let();m_e_price.Cardinality(1);m_o_prices.Get(i,m_e_price);m_o_prices.Set(i-1,m_e_price);
}
double _p=m_close.GetData(_x);
m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_p);m_o_prices.Set(0,m_e_price);
for(int i=0;i<m_transformations+1;i++)
{
double _a=0.0;
for(int ii=i;ii<m_functor_ab+i;ii++)
{
_a+=m_close.GetData(_x+ii);
}
_a/=m_functor_ab;
m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_a);m_o_average_a.Set(i,m_e_price);
//
double _b=0.0;
for(int ii=i;ii<m_functor_cd+i;ii++)
{
m_e_price.Let();m_e_price.Cardinality(1);m_o_average_a.Get(i,m_e_price);
double _b_i=0.0;m_e_price.Set(0,_b_i);
_b+=_b_i;
}
_b/=m_functor_cd;
m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_b);m_o_average_b.Set(i,m_e_price);
//
double _c=0.0;
for(int ii=i;ii<m_functor_ab+i;ii++)
{
_c+=m_close.GetData(_x+ii);
}
_c/=m_functor_ab;
m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_c);m_o_average_c.Set(i,m_e_price);
//
double _d=0.0;
for(int ii=i;ii<m_functor_cd+i;ii++)
{
m_e_price.Let();m_e_price.Cardinality(1);m_o_average_c.Get(i,m_e_price);
double _d_i=0.0;m_e_price.Set(0,_d_i);
_d+=_d_i;
}
_d/=m_functor_cd;
m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_d);m_o_average_d.Set(i,m_e_price);
}
for(int i=m_transformations-1;i>0;i--)
{
m_natural_transformations_ac[i]=m_natural_transformations_ac[i-1];
m_natural_transformations_bd[i]=m_natural_transformations_bd[i-1];
}
//
double _a=0.0;
m_e_price.Let();m_e_price.Cardinality(1);m_o_average_a.Get(0,m_e_price);m_e_price.Get(0,_a);
double _b=0.0;
m_e_price.Let();m_e_price.Cardinality(1);m_o_average_b.Get(0,m_e_price);m_e_price.Get(0,_b);
double _c=0.0;
m_e_price.Let();m_e_price.Cardinality(1);m_o_average_c.Get(0,m_e_price);m_e_price.Get(0,_c);
double _d=0.0;
m_e_price.Let();m_e_price.Cardinality(1);m_o_average_d.Get(0,m_e_price);m_e_price.Get(0,_d);
m_natural_transformations_ac[0]=_a-_c;
m_natural_transformations_bd[0]=_b-_d;
}
}
刷新函数有点复杂。我们从刷新收盘价格指针开始,因为它是第1范畴的基础。在将最新值指定给该范畴的单个对象之前,我们需要移动该对象中的所有现有元素。然后,我们对范畴2的两个对象做几乎相同的事情。这里的区别是,我们需要首先计算每个相应周期的移动平均值,一旦完成,我们就在像在范畴-1中那样移动两个对象的值后分配值。在这之后,我们必须处理第3范畴对象。它们是4个,但如前所述,我们只利用其中的2个进行预测。我们将从刚刚填充的两个对象中获得这些对象的值,并对DEMA公式进行轻微修改,该公式从移动平均值的两倍中减去移动平均值,我们将简单地计算前者。移动平均的移动平均。
一旦我们的专家跟踪类实例与MQL5向导组装好,我们的模型与测试运行的EURUSD每日价格数据的集成就完成了。和往常一样,这里有一个关于如何实现这一点的指南。如前所述,我们用动量振荡指标组装了这个 EA 交易,作为我们的专家信号类实例。