请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化策略 帖子:3364694 新帖:15

工作必须继续,再次讨论锯齿形调整浪

舞蹈家发表于:4 月 17 日 19:59回复(1)

简介

大量的锯齿形调整浪证实了,人们对此指标一直非常感兴趣。这是一个相当值得研究的主题。这可能是唯一一个能够直接影响交易者情感的指标,通过以图形的形式鲜明生动地显示主要的市场变动,迫使立即采取行动。很显然,这种现象只能解释如下:大多人都完全了解此指标并非用于产生直接交易信号,然而,直接交易信号一直在尝试将此指标与当前市场情况最大限度的相关联。能够观察到上一个预测裂缝的无限重绘未必是优势,尤其是正对其进行察觉时。

我们来稍作讨论。不管你是否相信,但它是一切事情的开端。

叙述

我们所有来到这个市场中的人迟早都会发现,市场并不像我们最初想象的那么简单。一旦我们认识到了这一点,我们就会开始阅读资料(当然是能够阅读的人)。但是,从某种程度上讲,我们发现自己阅读的资料会非常奇特。简而言之,我们会选择最简单的资料,而不是合适的资料。相应地,我们将仅在我们的工具库中添加很肤浅的东西,这些东西显然易于理解,而且可轻松(快速)地转换为算法语言。有很多这样的例子。下面是其中一个例子,可能不是最好的例子,然而,我们来看看它的真面目。

每个人都了解并记得基本的 TA 理论,这些理论尚未被反驳,但仍未获得严格的证实,然而:

价格是我们的一切!

在直接按字面意义理解这句话后,我们开始寻找的不是市场的控制点,而是通过所有方式实现价格的最大化和最小化 - 这更加简单明了。我们使用标尺绘制支撑/阻力位,基于这些位计算斐波那契位,计算柱中的循环等等。越来越糟糕的是 - 我们开始仅从某个人的交易系统中提取我们易于理解的东西,而没有注意到相关警告、此交易系统适用于哪个市场以及此交易系统的创建时间等因素。更糟糕的是,我们开始简化…简化 Gann (!!!) 的理论,是他(我认为)发现了(或者非常接近于发现了)价格/时间问题的解决方案,这简直是精神错乱,怎么能简化还尚未被任何人完全理解的东西?

然而,当我们意识到所有的一切在一定程度上都运行错误时,略好于 50% 概率,我们很可能又会大声说专家在骗人,他们的方法没有用,他们著书都是为了钱,黄金分割不存在等等。而出现这个结果是我们忘记了,极值不是最大值或最小值的同义词,但实际上又是最大值或最小值,只是采用了内在本质的另一个表现形式,我们仍需对其进行研究。因此,基于这种肤浅的看法,我们就开始试着分析未来,甚至都没有去分析这个结论(这就是正确的时间,正确的地点)从何而来。

尽管我们要赚钱,但这一点并不会妨碍我们,我们有时需要停下来稍作思考。你要知道,这是很有用的。你开始清楚理解“人类是唯一一种一遍遍地做同一件事却期待不同的结果的生物”的正确性。我们不是在砍柴,不是吗?:)

我被热情冲昏了头脑。我可能也会这样。该停下来了。只是让我们了解,并非所有专家都是真正的专家,而真正的专家不会告诉你所有的东西,尤其是他们知道,填鸭式的东西既不容易理解也没有多大帮助。

回到主题上来。

多帧分形锯齿形调整浪


我需要一个指标,此指标不仅仅显示最小值和最大值,还显示价格变动通过逻辑推理(LREP - 此缩写能否采纳?)得出的市场极值点,以及进行确认(如果可能)。起初,并没有提及使它成为交易信号产生器的问题。首先,我尝试了使用标准的(不是 MT4 中内嵌的,而是常规意义的“标准”)锯齿形调整浪,但有些问题使我警惕起来,迫使我放弃了这个想法:

  • 所有算法的一致性,尽管在互联网中有大量的讨论以及各种各样的版本(顺便说一下,问题可能在于我眼力不好,但我从未在任何地方见过这种清晰解码的算法);

  • 缺乏它应寻求的“目标”的概念;

  • 极其频繁的重绘,最糟的是重绘的可预测性不佳;

  • 直接依赖于时间范围和/或之前指定的价格偏移;

它让我有所顾虑,尤其是最后一点最不能接受。它对我没有吸引力。没有什么个人隐私。

我记得,Demark 有他的 TD 点,Williams 有他的“分形”(我不知道是谁借鉴谁的,但它们就像一个模子里印出来的)。看起来是同一个东西 - 它至少是使用先前和后续的价格变动推理而来的。可能,并非所有人都喜欢用这种方法来选择这些点。然而,还没有任何人发明出更准确的方法来对它们进行最初的识别,当然“重要的极值”、“局部极大值”等词语除外。

自己的东西可能不是更好的,但肯定是更“相似的”。这就是我没有求助借鉴的代码而是编写了自己的简单分形指标的原因,此指标更加准确,具有相似性:选择点的原则略微不同于标准原则。我尝试使用 iCustom 在不同的时间范围调用它,但随后认识到,在当前(工作)时间范围 (TF) 上计算所有内容则更为合理。再往前,编程逻辑提醒所有内容:关于未来自我预测的模块结构,以及不符合标准的 TF。下面是得出的结果。

下图显示了使用 TF 参数 1440、360、60 的外观。H1 图表被选择用于展示目的,从中你可以看到黑线 (60) 没有使用全部分形点,而是拒绝了一些分形点。第一个图片用于查看提示,第二个图片只是从图中的中间部分截取而来。

配色方案不是最好的方案,所附图片显示的是我对它的看法。


代码


我们来看看它是如何实现的 - 我们不应用手势表示吗?;)
指标在当前工作时间范围 (TF) 上形成一系列的锯齿形调整浪节点,将在三个模拟的较大 TF 上计算这些节点。它在所有 TF 上工作并使用所有 TF,包括不符合标准的 TF,并在代码中实行以下限制:
- 较大的 TF 必须能够被工作时间范围整除;否则,强制设置最接近的正确值;
- 工作时间范围不大于最小的较大 TF;
- 参数的周期以分钟为单位指定,并且必须按降序设置;
- 最大 TF 的周期不能超过 43200(一个月)- 这不是限制,更大的 TF 也可行;
此功能是,每个 TF 仅使用一个缓冲区。无需使用它们中的两项,因为在 TF 的合理组合中,在工作 TF 的单个条柱上,出现两个方向不同的极值的概率过小。

下面是此代码片段:

//-// MF_Fractal_ZZ_3in1.mq4//-#property copyright "Copyright © 2008, BiViSi Corp."#property link      "riderfin@bk.ru"#property link      "ICQ 499949112"#property indicator_chart_window    #property indicator_buffers 3// style of the indicator line#property indicator_color1 Blue 
#property indicator_color2 Red#property indicator_color3 Yellow        #property indicator_style1 0#property indicator_style2 0#property indicator_style3 0#property indicator_width1 5#property indicator_width2 3#property indicator_width3 1// INOUT PARAMETERS OF THE INDICATORextern int VolExt=50; // VolExt+1" calculation of the last control pointsextern int TFLarge=1440;extern int TFMidle=240;extern int TFSmall=60;// Variables double Large[],Midle[],Small[];  // control points (indicator bufers)datetime PrevTimePer[4];         // the time of the last calculation of every TFdatetime PrevTimeCalc=0; 
double P60,CP60;int CurPeriod, ErrorTF=0, NumberExt, Per,  largelast=0, midlelast=0, smalllast=0;//-int init() 
{
   // initialization   IndicatorBuffers(3); // for perspective" entry :)   SetIndexBuffer(0,Large); SetIndexStyle(0,DRAW_SECTION);
   SetIndexEmptyValue(0,0.0);
   SetIndexBuffer(1,Midle); SetIndexStyle(1,DRAW_SECTION);
   SetIndexEmptyValue(1,0.0); 
   SetIndexBuffer(2,Small); SetIndexStyle(2,DRAW_SECTION);
   SetIndexEmptyValue(2,0.0);
   ArrayInitialize(PrevTimePer,0);
   CurPeriod=Period(); CP60=CurPeriod*60;
   // restrictions:   // control of TF and inputted parameters   if (MathCeil(TFSmall/CurPeriod) != TFSmall/CurPeriod) 
      TFSmall=MathCeil(TFSmall/CurPeriod)*CurPeriod;
   if (MathCeil(TFMidle/CurPeriod) != TFMidle/CurPeriod)
      TFMidle=MathCeil(TFMidle/CurPeriod)*CurPeriod;
   if (MathCeil(TFLarge/CurPeriod) != TFLarge/CurPeriod)
       TFLarge=MathCeil(TFLarge/CurPeriod)*CurPeriod;
   if (CurPeriod > TFSmall) 
      {Alert ("The chart period must be less than or equal to ", TFSmall," min.");
       ErrorTF=1;return;}
   if (TFSmall >= TFMidle || TFMidle >= TFLarge || TFLarge>43200)
      {Alert ("Incorrect choice of timeframes for calulation!!!"); ErrorTF=1;return;}
   return;              
}//

下一个块负责控制点搜索、锯齿形调整浪节点计算以及将它们写入指标的缓冲区数组。


是否拒绝使用 int IC=IndicatorCounted(); 等类型的结构取决于计算算法本身,不使用可以提供足够的速度(见代码中的 Force #1-3),也可以增加,顺便提下,稍后将介绍。

//int start()
{
   if ( ErrorTF==1 ) return; // incorrect timeframe   FractalCalc(); 
   return;
}//======================================================================// Searching of the 5 bar fractals and zigzag nodes claculation// on the emulation of the larger TF, deleting of the odd ones and representation on the current TF//======================================================================void FractalCalc ()
{   
   // Force  №1 - caculation only on the fully formed bar of the working TF   if (PrevTimeCalc == Time[0]) return; else PrevTimeCalc=Time[0];
   int y, x, k, i, j, extr=0; 
   // the time of the last bar of the current TF, that closes bar №1-5 of the larger TF   int t1, t2, t3, t4, t5;                     
   // the number of the last bar of the cur. TF, that closes bar №1-5 of the larger TF   int limit1, limit2, limit3, limit4, limit5; 
   // the numver of bars of the cur. TF with the peaks and bases that correspond with the bars 1-5 of the larger TF   int up1,up2,up3,up4,up5,dn1,dn2,dn3,dn4,dn5;
      
   for (y=1; y<=3; y++) // cycle of the calculated TF      {
      if (y==1) Per=TFLarge; if (y==2) Per=TFMidle; if (y==3) Per=TFSmall;
      P60=Per*60;
      // Force №2 - calculate the fissures only with the forming of the bar of the larger TF      if (PrevTimePer[y] !=0)
         { 
         if (Per<43200 && (Time[0] - PrevTimePer[y])<P60 )continue;
         if (Per==43200 && Month()==TimeMonth(PrevTimePer[y]))continue;
         }
      // Processing of bars absence      // If linearly PrevTimePer[y]=Time[0], then in case of bar absence      // the shift of whole calculation chain by the absence size will take place on the working TF      PrevTimePer[y]=MathCeil(Time[0]/Per/60)*P60; 
      
      NumberExt=0;  extr=0;
      k=Per/CurPeriod;
      // limitation of cycle depending on currently calculated TF      // and on the last fractal      i=MathCeil(Bars/k)-5;
      // Force #3 - calculation starting with the last fissure      if(y==1 && largelast !=0) i=largelast+k;
      if(y==2 && midlelast !=0) i=midlelast+k;
      if(y==3 && smalllast !=0) i=smalllast+k;
      for (x=1; x<=i; x++) 
         {
         // find peaks and bases         // the time of the beginning of the las bar of the cur. TF, that closes bar №1 of the larger TF         if (PrevTimePer[y] !=0) t1=PrevTimePer[y]-x*P60+(k-1)*CP60;
         else t1=MathCeil(Time[0]/Per/60)*P60-x*P60+(k-1)*CP60;
         t2=t1-P60; t3=t2-P60; t4=t3-P60; t5=t4-P60;
         limit1=iBarShift(NULL,0,t1, false); limit2=iBarShift(NULL,0,t2, false);
         limit3=iBarShift(NULL,0,t3, false); limit4=iBarShift(NULL,0,t4, false);
         limit5=iBarShift(NULL,0,t5, false);         
         up1=iHighest(NULL,0,MODE_HIGH,k,limit1); up2=iHighest(NULL,0,MODE_HIGH,k,limit2);
         up3=iHighest(NULL,0,MODE_HIGH,k,limit3); up4=iHighest(NULL,0,MODE_HIGH,k,limit4);
         up5=iHighest(NULL,0,MODE_HIGH,k,limit5);
         dn1=iLowest(NULL,0,MODE_LOW,k,limit1); dn2=iLowest(NULL,0,MODE_LOW,k,limit2);
         dn3=iLowest(NULL,0,MODE_LOW,k,limit3); dn4=iLowest(NULL,0,MODE_LOW,k,limit4);
         dn5=iLowest(NULL,0,MODE_LOW,k,limit5);

         // searching for control points         if(High[up3]>High[up2] && High[up3]>High[up1] && High[up3]>=High[up4] && High[up3]>=High[up5])
            {
            if (y==1){Large[up3]=High[up3];largelast=up3;}
            if (y==2){Midle[up3]=High[up3];midlelast=up3;}
            if (y==3){Small[up3]=High[up3];smalllast=up3;}
            NumberExt++;  extr++;
            }
         if(Low[dn3]<Low[dn2] && Low[dn3]<Low[dn1] && Low[dn3]<=Low[dn4] && Low[dn3]<=Low[dn5])
            {
            if (y==1){Large[dn3]=Low[dn3];largelast=dn3;}
            if (y==2){Midle[dn3]=Low[dn3];midlelast=dn3;}
            if (y==3){Small[dn3]=Low[dn3];smalllast=dn3;}
            NumberExt++; extr++;
            }
         if (NumberExt>VolExt) break;   
         } 
      }




正如你所看到的,代码的大部分旨在优化计算和防止出现可能的意外情况 - 历史记录中丢失服务器连接和丢失条柱。

下一个块执行一种“清理”操作:删除奇数极值(当两个波峰之间出现多个波谷时,反之亦然)以形成一个正确的锯齿形调整浪:从后续接连 2 个或更多波峰/波谷之间选择最大/最小项,如果相等,则选择编号最小的项,奇数项将被设置为零。算法为参数提供空间,当然替代项也是可行的,但我目前决定这样做。

代码包含带注释的条目,这些条目能够消除不同 TF 上出现的波峰/波谷的不一致性,但需要为代码提供再一次更新,它在当前格式中无法正常工作。我暂时保留此观点,但如果你感兴趣,可以自己做。

如果使用了之前计算的偏移的 if (NumberExt>VolExt) break; 结构,相同的片段还可能会加快工作速度,但我暂时仍保留此观点。

一旦我们开始讨论速度,最明显和最容易的方法就是降低指标输入中的 VolExt ;很少有人需要超过 10-15 项进行交易,并不适于进行分析,但真正的特殊爱好者除外 :)。

   if (extr==0) return;
   for (y=1; y<=3; y++)
      {
      if (y==1) j=ArraySize(Large);if (y==2)j=ArraySize(Midle);
      if (y==3)j=ArraySize(Small);      
      int min=0, max=0, extmin=0, extmax=0;
      NumberExt=0;      
      for (x=1;x<=j;x++)
         {
         if (y==1)
            {
            if (Large[x] == 0.0 ) continue;
            if (Large[x] == High[x])
               {
               NumberExt++; extmax++; extmin=0;
               if (extmax==2)
                  {
                  if (Large[max]>=Large[x])Large[x]=0.0;
                  else {Large[max]=0.0;max=x;}
                  extmax;  
                  }
               else max=x;
               }
            if (Large[x] == Low[x])
               {
               NumberExt++; extmax=0; extmin++;
               if (extmin==2)
                  {
                  if (Large[min]<=Large[x])Large[x]=0.0;
                  else {Large[min]=0.0;min=x;}
                  extmin;  
                  }
               else min=x;
               }
            }         
         if (y==2)
            {
            if (Midle[x] == 0.0 ) continue;
            if (Midle[x] == High[x])
               {
               NumberExt++; extmax++; extmin=0;
               if (extmax==2)
                  {
                  if (Midle[max]>=Midle[x])Midle[x]=0.0;
                  else {Midle[max]=0.0;max=x;}
                  extmax;  
                  // it can be easier as the above one, but.... remove disagreements                  /*
                  if (Midle[max]>Midle[x])Midle[x]=0.0; 
                  if (Midle[max]==Midle[x])
                     {
                     if (Large[x] == High[x]) {Midle[max]=0.0;max=x;}
                     else Midle[x]=0.0; 
                     }
                  if (Midle[max]<Midle[x]){Midle[max]=0.0;max=x;}
                  */                  }
               else max=x;
               }
            if (Midle[x] == Low[x])
               {
               NumberExt++; extmax=0; extmin++;
               if (extmin==2)
                  {
                  if (Midle[min]<=Midle[x])Midle[x]=0.0;
                  else {Midle[min]=0.0;min=x;}
                  extmin;  
                  // it can be easier as the above one, but.... remove disagreements                  /*
                  if (Midle[min]<Midle[x])Midle[x]=0.0; 
                  if (Midle[min]==Midle[x])
                     {
                     if (Large[x] == Low[x]) {Midle[min]=0.0;min=x;}
                     else Midle[x]=0.0; 
                     }
                  if (Midle[min]>Midle[x]){Midle[min]=0.0;min=x;}
                  */                  }
               else min=x;
               }
            }         
         if (y==3)
            {
            if (Small[x] == 0.0 ) continue;
            if (Small[x] == High[x])
               {
               NumberExt++; extmax++; extmin=0;
               if (extmax==2)
                  {
                  if (Small[max]>=Small[x])Small[x]=0.0;
                  else {Small[max]=0.0;max=x;}
                  extmax;  
                  // it can be easier as the above one, but.... remove disagreements                  /*
                  if (Small[max]>Small[x])Small[x]=0.0; 
                  if (Small[max]==Small[x])
                     {
                     if (Midle[x] == High[x]) {Small[max]=0.0;max=x;}
                     else Small[x]=0.0; 
                     }
                  if (Small[max]<Small[x]){Small[max]=0.0;max=x;}
                  */                  }
               else max=x;
               }
            if (Small[x] == Low[x])
               {
               NumberExt++; extmax=0; extmin++;
               if (extmin==2)
                  {
                  if (Small[min]<=Small[x])Small[x]=0.0;
                  else {Small[min]=0.0;min=x;}
                  extmin;  
                  // it can be easier as the above one, but.... remove diagreements                  /*
                  if (Small[min]<Small[x])Small[x]=0.0; 
                  if (Small[min]==Small[x])
                     {
                     if (Midle[x] == Low[x]) {Small[min]=0.0;min=x;}
                     else Small[x]=0.0; 
                     }
                  if (Small[min]>Small[x]){Small[min]=0.0;max=x;}
                  */                  }
               else min=x;
               }
            }         
         if (NumberExt>VolExt) break;
         }
      }         

}

总结


结果是,我们获得了一个带算法的指标,此指标可能很明显,但之前从未被任何人用过,可消除标准锯齿形调整浪的一些缺点,同时具有以下优点:

  • 节点重绘相对少一些,针对波动和之前价格变动的重绘合理。与此同时,如果它们在不同的 TF 上重合,则不会进行重绘的可能性有 90-95%;

  • 能够观察到在单个图表上三个较大 TF 上发生的所有事情,因此,能够在不使用任何其他结构或工具的情况下发现主要趋势;

  • 使用任何不符合标准的 TF(从 M5 到 MN1)进行锯齿形调整浪计算,可满足任何偏好和需求;

  • 高效,计算速度高,算法明确,代码可轻松更正和改进。

你可能会问我,我自己为什么没有立即进行更正。对我而言,我目前得到的已经足够……此时足矣。:)
我知道,一个完成的高效代码可以进行无数次的更新。它就像削铅笔,你可以忽略掉你要用它来画画。我要开始画画。我非常需要它!:)

下一次是什么?我们又应如何处理它?没有一成不变的解决方案。这只是个工具,应使用它做什么,是匹诺曹还是凳子,每个杰佩托都将有自己的决定。
我只能说,剩余空间包含 5 个可用的指标缓冲区,能够轻松地添加新模块,并能够对通过 iCustom() 的调用做出充分的响应。


全部回复

0/140

量化课程

    移动端课程