解读经典和隐藏背离的新途径。 第二部分

18 十月 2019, 15:42
Alexander Lasygin
0
5 174

概述

在首篇文章中,我们研究了一种解读背离的非标准途径。 我们分析了一些与之相关的图形结构,并简要触及了背离本身,背离识别品质,以及它的分类。 然而,本文没有涵盖基于形态对成交的交易进行过滤。 不过,我们习以为常的说法其实一直含糊不清。 经典背离形式仍然有效吗? 行情也许已经发生了极大变化,以至于这种方法已不再适用。 在这一部分中,我们将针对经典、及非标准版本的解读进行更深入的研究。 我们将尝试针对这个策略作出判研。 如果结果是正面的,我们将尝试提高其有效性。

术语和定义

在继续进入主要部分之前,我要提及一些前置知识,作为本次研究的基础,并解释其“非标准”性质。 我曾在一群志同道合的人组成的团队中担任技术分析师,这群人试图根据背离原理创建交易机器人。 我的任务是收集最大数量的相关数据,解析现有的技术分析工具,并确定最合适的变体。

我还必须在信号形成后,考虑事件的后续可能发展。 我所有的研究和分析都是在浪费时间和精力。 期望的结果应通过思考获得,而非浪费 CPU 和人力资源。 不过,我的研究取得了积极的成果。 创建了有别于现存指标的指标,一些复杂的技术分析概念得以修改或排除。 背离作为形态变得充满活力并且被简化:不管它是否存在,以及是否为 A,B,C 之类的类别均被消除了。

背离作为一种信号获得了新生。 在进行这项工作的过程中,任何形式的背离变得更清晰、更平滑,亦或重新计算时无关于市场行为。 这是一次令事实符合我们观点的尝试。 我们的目标不是撰写大量的研究论文。 主要目的是检验此形态是否适合进行交易。 我们将在稍后返回。 搜索相关数据没有得到结果。 其他作者接收基本信息时似乎来自相同的源头。

Alexander Elder 在他的《技术分析中的最强信号》一书中对基于此原理的策略进行了最详细的阐述,该著作里描述了背离和趋势逆转。 读完这本书后,我产生了更多问题。 作者设定了一个强制性条件:指标必须与零轴交叉,然而,在“缺少右肩”一章中,他又说这是背离的可选条件。

那一时刻,MetaStock 终端尚未提供线性 MACD。 代之,在终端子窗口中绘制了两条均线,且与零轴没有任何绑定。 结果造成它无法按作者描述的方式使用。 Elder 使用了一个 MACD 版本,该版本在 MetaTrader 4/5 终端中称为 OsMA,但整本书中都称之为 MACD。 没有趋同(逆背离)的描述。 在此,术语“趋同(convergence)”仍然描述为价格行为和指标之间的背离。 此外,Elder 拒绝使用其他没有均衡线(零轴交叉)的指标来进行分析。 特别提到了随机震荡(Stochastic)指标。

为了进行更深入的分析,其他作者将主要形态分为三个子组 A、B 和 C。其思路是,背离越大,信号越大,因此根本不必考虑趋同。 这个想法真的有效吗? 我在之前的资料中以相关分布作为示例。 解释为何我不同意这种等级,超出了第一部分的范畴,因此决定原样保留所有内容。

这些术语中的大多数将不会用到,而其中一些仅用于描述正在发生的事情概况。 阅读这些资料后,您也许会认为实际上存在背离,而背离-趋同分布仅在上一篇文章中所描述的其他图形构造的上下文中得以研究。 背离本身有条件地分为“停止”和“逆转”。 为什么要有条件地划分? 该信号本质上是一个停止信号。 然后,确认信号可以显示行情是否会逆转。

我们来考察一些例子。

A 类背离

被认为是最强的。

熊市 — 新价格高点高于先前的高点,而新的指标高点则低于其先前的高点。

牛市 — 新价格低点低于先前的低点,而新的指标低点高于其先前的低点。


图例 1

这种背离可于强劲的价格走势(冲量)之后观察到。 通常,这种冲量是新趋势出现的信号,这意味着 A 类背离依其“强度”抵消了该规则,并抵消了市场行为的惯性,通常来说,即整体波浪理论。 上图的右半部分可能会令人怀疑是否正确检测到形态。 以下图例似乎毫无疑问。


图例 2

如此开始可能会导致两个、三个或更多的背离。 冲量越强,趋势可以持续的时间越久。 这与背离越大,信号越强的想法相矛盾。

B 类背离

一个不太重要的行情信号。

熊市 — 图表高点处于同一水平,而右侧震荡器高点低于左侧震荡器高点。

牛市 — 价格高点处于同一水平,而指标右腿高于左腿。

这会令您产生什么联想? 这是经典烛条形态“双顶”和“双底”。 在来源中,它被描述为“强劲的市场逆转形态”。 所以,这是一种逆转形态,而非终止形态,属于主要的五种形态。


图例 3

最后一个子类型。

C 类背离

它被认为是最弱的。 有观点认为,这种形态应予以忽略。

熊市 — 价格图表上形成新高,而指标高点处于同一水平。

牛市 — 价格形成新的低点,振荡低点相等。


图例 4

通常在所谓的“假突破”或市场参与者行动频繁的区间,能在强阻力和支撑位观察到这种价格行为。 它与指标的滞动相关。 尽管不能将该信号视为无争议入场点,但仍不应忽略它。

还有许多其他背离和矛盾之处,由于这些原因,我决定更详细地研究这类背离。 我们不会大范围内更改术语和概念,以免误导熟悉它们的人,以及继续学习相关资料的人。

我们来分析一下我们的指标。

MACD

MACD 指标由 Gerald Appel 创建,用于股票价格分析。 该指标在交易员中非常受欢迎。 受欢迎是出于其有效性经历多年测试的事实,因此,拥有众多的相关资料。 顾名思义,“移动平均收敛/发散”,似乎是专门为此目的而设计的。 指标有两种:线性 MACD 和 MACD 直方图。 

线性 MACD:

  • MACD=EMAsn-EMAln
  • Signal=EMAmacd
  • MACD Histogram:
  • MACDn=Signal-MACD

其中:

P 是价格,通常等于该期间的收盘价,但也可以使用其他选项(开盘价,最高价,最低价,收盘价,中间价,典型价格,等等)。

默认情况下使用以下 MACD 设置:

  • ЕМАs — (短线),周期 12 天(两周)。
  • ЕМАl — (长线),周期 26 天(一个月)。
  • EМАa — (平滑差价),周期为数值 9。 

两种版本均在 MetaTrader 5 中提供,但它们具有不同的名称:MACD 和 OsMA。 必须记住,终端中的 MACD 是线性 MACD,而 MACD 直方图由 OsMA 表示。

  

图例 5

我们来考察两种类型。

MetaTrader 5 MACD 体现为趋势指标,因此,预期经典背离必须准确反映趋势结束。 然而,并非那么简单。 这不仅源于不同的指标解释规则,还源于形态类型的多样性。 在第一部分中,我说过零轴交点是总体趋势结束的明确标志。 这不是真的。 还有一种观点认为,略微的零轴出头能得到更强的逆转信号。


图例 6

在这种情况下,零轴交叉是强制性条件。 特别是,Alexander Elder 对此观点表示赞同。 不过这并非最广泛的争议。 这两个规则均可使用,但是如果有特定的市场状况,则应在框架内考虑应用每条规则。

不过,主要问题与形态的定义有关。 我们的振荡器基于烛条收盘价,那么为何我们要寻找新的高点和低点?

  

图例 7

  

图例 8

  

图例 9

哪种方法正确? 价格或指标值哪个更重要? 该指标的另一个缺点是计算周期较长,26-12,令其不适合价格窄幅波动的行情。 依据经典背离含义,应该在指标值中找到一对分形,并将它们与价格走势进行比较。 不过,分形不会在较小的价格走势中形成。 为了清楚起见,我们要改进标准版本。 我们会根据走势方向,以不同的颜色绘制这些线条。 这并不困难。 我们来修改标准代码。 这一行

#property indicator_buffers 4

4 改为 5

#property indicator_buffers 5

#property indicator_type1   DRAW_HISTOGRAM

改为

#property indicator_type1   DRAW_COLOR_HISTOGRAM

以及

#property indicator_color1  Silver

改为

#property indicator_color1  Green,Red,Gold

在变量中添加另一个缓冲区

double                   Color_buff[];


现在初始化块如下所示

   SetIndexBuffer(0,ExtMacdBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,Color_buff,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,ExtSignalBuffer,INDICATOR_DATA);
   SetIndexBuffer(3,ExtFastMaBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,ExtSlowMaBuffer,INDICATOR_CALCULATIONS);

此处 

   SetIndexBuffer(1,Color_buff,INDICATOR_COLOR_INDEX);


不能在末尾添加,因为它必须索引为 1,否则将不起作用。

现在,要识别分形,我们至少需要 3 根烛条,所以我们将计算柱线数量有关的模块进行相应修改。

if(prev_calculated==0)
      limit=2;
   else limit=prev_calculated-1;

在主模块中添加几行

//--- calculate MACD
   for(i=limit;i<rates_total && !IsStopped();i++)
     {
      ExtMacdBuffer[i]=ExtFastMaBuffer[i]-ExtSlowMaBuffer[i];
      //--- calculate Color Macd
      if(ExtMacdBuffer[i]>ExtMacdBuffer[i-1])
         Color_buff[i]=0.0; // set color Green
      else
         Color_buff[i]=1.0; // set color Red
     }
//---


最后,我们添加一个判断 MACD 极值的模块。 为避免重绘,此操作将在当前柱线收盘后完成。 为此,将移至一号柱线进行计算。

for(i=limit;i<rates_total-1 && !IsStopped();i++)
     {
      if((ExtMacdBuffer[i-1]<0 && ExtMacdBuffer[i]>ExtMacdBuffer[i-1] && ExtMacdBuffer[i-1]<ExtMacdBuffer[i-2]) || 
         (ExtMacdBuffer[i-1]>0 && ExtMacdBuffer[i]<ExtMacdBuffer[i-1] && ExtMacdBuffer[i-1]>ExtMacdBuffer[i-2]))
         Color_buff[i-1]=2.0; // set color Gold
     }

这个变体意味着当 MACD 线高于零轴时,我们仅识别向上分形; 当 MACD 低于零轴时,仅检测向下分形。 大错特错。 将来,我们会使用该变体,其中分形类型(向上或向下)不取决于主指标线相对于零轴的位置。

在已有形态中某些时刻的自动化是不可能的,因此只有视觉观察才能给出积极的结果。

  

图例 10

在 Expert/Signal/SignalMACD 类中为弥补此缺陷进行了尝试。 该文档包含以下内容:

  • 背离是指振荡器分析的首个波谷比前一个还浅,而相应的波谷价格比前一个波谷价格更深。
  • 双重背离是指振荡器形成三个连续波谷,每个波谷都比前一个波谷浅。 而价格形成了三个对应的波谷,每个都比前一个深。


 图例 11

再有,“振荡器分析的第一个波谷比前一个波谷更浅,相应的波谷价格比前一个波谷价格更深”的描述令我们回到了“先有鸡或先有蛋”问题。 哪一个先到?价格行动还是指标值? 基于价格值形成的指标值因何比价格序列更重要? 此外,该叙述不能提供任何特定信息。 计算中应使用多少根柱线:三根、五根或整个历史记录? 该方法可以归类于非标准方法,但是在经典版本中实施该方法弊大于利。 但是,不应完全拒绝它。 在某些特定情况下,只有此指标适合。

作为自动化变种之一,我们可以考虑同时使用 MACD+OsMA。 OsMA 指标的改进与 MACD 相似。


图例 12

正如我们所知,OsMA 与 MACD 相同,但显示的直方图是 MACD 信号线和主线之间的差值。 OsMA 比 MACD 更为敏感,但它尚有不总,因此指标会丢失信号。 但有时它过于敏感,因此需要额外的确认。

  

图例 13

当使用两个指标时,先要确定它们中的哪一个应优先考虑,另一个作为补充;即应将哪个指标的背离视为强制性的,而另一个则是可选的。 

还有,我认为另一个缺点是选择指标参数的能力。 如果 RSI 计算周期仅影响曲线幅度,那么对于 MACD、OsMA、Stochastic,则会改变外观。 可能有人会说:“市场状况正在发生变化,这种可能性是必要的,而该指标是为股票市场创建的,并且其参数是为一小时的周期而选择的”。 但是我要说的是:这种可能性并非普适的,而是与拟合有关。

当然,在初始状态下可能需要一组用于特定品种和图表周期的参数,但如果指标随后变得无效,则最好停止一起使用。 但这纯粹是我个人的观点。 在第一部分资料中使用 AC(加速器/减速器)指标的原因之一,即该指标缺乏“过度拟合”的可能性。 这并非唯一可能的指标。 所有指标都有其特殊的优点。 前面针对 AC 所描述的所有规则,对于所有其他指标均适用。 我们在经典背离的背景下分析了以上内容,但它也适用于逆转/隐藏背离规则。 如您所见,并非所有经典思想都是无可怀疑。 那么,这种传统形式的工具可以用作高质量信号吗?

在回答这个问题之前,我们看一下其他指标,这些指标通常用于解决上述任务。

Stochastic(随机振荡)

Stoсhastiс 振荡器是一款技术指标,以百分比的形式衡量价格冲量。 “随机一词是指当期收盘价相对于一段时间内其价格范围的差值。” ,该指标由乔治·莱恩(George Lane)于 2007 年 3 月创建。

它由两条曲线组成:

  • %K Period — 快速随机(实线)。 搜索低点/高点的柱线数量。
  • %D Period — 慢速随机指标(虚线)。 应用于 %K.的 SMA 周期
  • Slowing — 此参数与 %K 有关。 它设置平滑参数。
  • %K=((CLOSEn-LOWn)/(HIGHn-LOWn))*100

其中:

  • CLOSEn — 前期收盘价:
  • LOWn    —  最近 n 个周期的最低价格
  • HIGHn   —  最近 n 个周期的最高价格
  • %D         — %K.的移动均线 该均线可以使用不同的均化方法:简单均化,指数均化,平滑或线性加权均化。 也可以更改价格序列:高/低或开盘/收盘价。

该定义包含单词“背离”。 如果 MACD 的思路很清晰,那么使用常规化振荡器就略微难以理解。 可以将“常规化振荡器”这一概念定义为在刚性框架中更改其数值。 在我们的例子中,框架是从 0 到 100。 该功能设置特定条件。 数值标尺上突出显示了三个区域。 这些是超买区域(80%),超卖区域(20%)和主要走势。 计算细化创造条件,在该条件下,指标线不会长时间停留在极限区域,且不会进入极限区域。


图例 14

似乎可以使用两种不同的价格范围来解决 MACD 使用哪个价格范围的有关问题。 这里产生了另一个问题。 从图例 14 中可以看出,基于收盘价的随机指标比基于最高/最低价的指标更频繁地触及极值位置 “100 - 0”。 这与指标计算公式有关。 我们还观察到许多波峰和波谷。


图例 15 

对于这些情况,没有明确的规则。 结果就是,在 100-100 和 92,31-92,22 之间的背离很难自动化。 在典型的计算版本中,使用两个最接近的分形。 在我们的情况下,这些都不是最接近的分形。 但是,“每条规则都有例外”。 因此,我们可以将缺点转变成优点。 根据计算周期更改设置,我们可以将 M15 图表的变化反映在 M5 图表上。


图例 16

此选项的优点是,我们可以轻松地自动进行全局(扩展)市场分段中的背离检测,并得到无延迟的早期入场信号,并等待更高时间帧的烛条收盘进行协助。 这些分段在图例 16-17 中用红线显示。 在某些情况下,这可能至关重要。


图例 17

从上图可以清楚地看到,如果我们根据 MTF 信号入场,那么我们的成交会亏损,而备选项则令我们获利。 类似的方法对于 MACD 也有效。


图例 18

除了显著减少信号数量之外,该解决方案还可以大幅增加获利成交的概率,从而提高总体获利能力。 我们已看到了 М5-М15 的例子。 如果我们使用 M5-H1 会怎样?


图例 19

使用快速和慢速随机值只能解决部分问题。 基于此类原理创建智能交易系统时,我们会遇到与使用快速和慢速 MACD(MACD + OsMA)相同的问题。 如何确定优先级? 这并没有解决创建背离指标时如何过滤随机指标线突破丰度的主要问题。 我们无法承受每次突破都去检验。 这会产生过多的噪音,因此我们不得不将其限制在两个,少量情况下是三个。

稍后我们将回到信号过滤问题。 现在我们来重点讨论寻找背离时应注意的规则。 稍后会提供一个解释,说明为什么我们没有设置明确的“否”。

1) 从逻辑上讲,我们知道在得到背离(趋同)之前,价格必须达到临界值。 相应地,指标线也需要达到临界水平。 在我们的情况下,指标必须进入超买/超卖区域。 在这种情况下,行情达到新的最高/最低价是可选条件。 在我们的情况下,搜索经典背离时,距当前柱线的第二个点(左侧)必须位于此区域中。 相反,对于隐藏的(逆转)背离,第一点应处于临界水平。


图例 20

2) 搜索信号时(手工或通过算法),搜索最接近极值所需分段应排除图例 20 中情况。 这种序列的最大数目是三个。

图例 21

尽管图例 15 似乎对应于规则 1,其中左侧遴选位置处于超买区域,但存在三个以上的指标点会取消该信号。

 

RSI 

这是可在我们的研究中使用的另一个指标。 您也许已经注意到,每个步骤的任务变得更加艰难。

RSI(相对强度指数)是 J.Welles Wilder 于 1978 年 6 月推出的指标。

RSI=100-100/(1+U/D)

其中: 

  • U 是平均价格在正数范围内的变化值 (CLOSEn>CLOSEn-1 ) 
  • D 是平均价格在负数范围内的变化值 (CLOSEn<CLOSEn-1 ) 
我们使用上面的公式,它与下面所显的原始公式不同:
  • RSI=(SMMAn)ofU(SMMAn)ofD
  • n - SMMA 计算周期。

它也会在 0-100 范围内常规化。 但是,与随机指标不同的是,它不包含曲线平滑选项。 这令分析变得复杂。 过度的灵敏度会导致大量突破。 如下图所示,指标仅在价格的持续单边走势中才保持单项线性走势。 在其他情况下,它是锯齿状的曲线。

  

图例 22

结果造成在这种情况下,过滤指标值的需求变得更加关键。 现在,我们查看问题解决方案之一。

我们已提过这两项哪个为主的问题:价格序列或指标值。 在这种情况下,我们必须找到答案。 没有太多可以帮助分析价格行为的工具。 其中包括不同类型的均线,分形和之字折线。

分形 (由 Bill Williams 创立)

标准变体包含五分形变体。 但是,这种分形不能解决滤波问题。 相反,由于信号与指标主线的偏差,所以有时反而混入了更多的噪音。


图例 23

与 RSI 类似,它会在横盘区域中产生很多信号,因此需要对其进行滤波。 另一个缺点是它的结构由五根柱线形成,故产生了延迟。 延迟等于至少一根烛条,这是极其不希望的。

均线是一种出色的平滑工具。 但是它有很多变种。 均线的不同之处在于平滑选项:SMA(简单平均),EMA(指数平均),SMMA(平滑平均),LWMA(线性加权平均); 使用价格:收盘价,开盘价,最高价,最低价,中位价((最高价+最低价)/ 2),典型价位((最高价+最低价+收盘价)/ 3),加权价位((最高价+最低价+收盘价+收盘价)/ 4 );而对于计算周期,范围从 1 到 ∞。 这涉及经典均线(移动平均值)。 此外,还有一个双重指数移动平均线。 MetaTrader 5 标准软件包之外还存在更多类型。 我们勿需布置 “分析所有背离搜索算法的所有可能选项,从而找到最佳版本” 的任务。 

之字折线(ZigZag)是“用于确定价格波动中的极值价格的指标,其幅度和周期根据过滤器偏差设置”。

根据定义,这就是我们需要的。 同样的问题在此也会发生。 RSI 基于收盘价,而之字折线则使用最高价/最低价。


图例 24

基于中位价((高+低)/ 2)创建 RSI,可以部分克服此缺点。


图例 25

从图例 24 可以看出,指标分形和价格分形的位置偏差不超过两根柱线,因此可以通过软件轻松地进行补偿。 请注意,在我们的案例中,我们仅对信号形式感兴趣,而非对其数值感兴趣。 也就是说,基本指标仅用于检测背离,而不用作独立的交易信号。

所以,我们可以按自己指定的背离设置来 “游戏”。 已知 RSI 计算周期不会影响信号形式,只会影响幅度,而之字折线设置不会改变极值的位置,我们可以达成惊人的结果。

根据应用于随机指标的规则:“在形成背离形态之前,指标值必须达到超买/超卖临界值”。 在我们的案例中,这些区域是 30 以下和 70 以上的区域。 此处,通过修改之字折线参数,我们可以同时获得短线信号及其全局值。 这些参数可以相互补充,因此 2+1(两个滤波器+一个基础)的组合可以跟踪整个画面。 过滤器的数量不限于两个,且可以等于三个或更多。 此外,当我们考虑目标价位时,我们会看到通过将信号分为若干组,我们将能够通过交易特定信号来捕获大部分行情走势。


图例 26

在图例 26 中,第一个信号中的 RSI 没有进入超卖区域。 我们可以简单地更改计算周期,从而增加幅度 — 在这种情况下,RSI 将出现在相应的区域中。

CCI

商品通道指数属于振荡器类型。 它由 Donald Lambert 于 1980 年开发。  

CCIn=(1/0.015)*((TypicalPrice-SMA)/MedianDeviation)

该指标的优点之一是其冲量特征。 因此,它不仅可以确定超买/超卖行情状态,还可以确定初始行情冲量。 在我们的案例中,这种优势可以被认为是缺点。 尽管其经典版本是根据“典型价格”计算的,但它仍然具有类似于 RSI 的锯齿状曲线。 因此,RSI 应用程序细则也适用于 CCI。 价格序列不仅需要按类型(最高价、最低价、收盘价,等等)进行过滤,还需要根据价格极值检测。


图例 27

由于这种行为,在寻找背离时,如果有多线突破,我们需要更改算法。


图例 28

其他指标罕有发生类似情况,但 CCI 却经常发生。

由于行为特殊,根据第一篇文章中描述的原理,该指标被认为是最佳的操作工具之一。 原理如下:“在价格图表上,自最后一个逆转背离(最后的多头和空头)绘制延伸的指示线,作为价格支撑/阻力线(图例 29),或者,若经典指标绘制在振荡器窗口的情况下,则支撑/阻力指标线绘制在振荡器窗口(图例 30)”。


图例 29


图例 30

冲量(Momentum) 

冲量反映价格变化率。 该指标的另一个名称是 RoC(变化率)。 它们之间的区别如下:RoC 中的均衡线为 0,而冲量的均衡线为 100。 John Murphy 在他的《期货市场的技术分析》一书中描述了该指标。

Momentum=Pn-Pn-1

其中 Momentum 是在时间 t(当前时间段)的 n 个周期内的冲量

这个变体不是很方便,因为它提供的数据来自资产价格。 因此,该公式得到了补充。

  • Pt  — 当前价格
  • Pt-n — n 个周期前的价格
  • RoCtn=(Momentum/Pt-n)*100

标准冲量实际上是 RoC,而 RoC 是常用的冲量-100。 指标计算原理在于对冲量走势的评估。 所以,它有如 CCI 和 RSI 相同的难题:锯齿线。 在此,这种走势会产生更多的信号。


图例 31

目前尚不清楚如何处理如此大量的信号。 自动版本也可能无法正常工作,如图例 31 所示。 根据有关该指标的现有信息,未将其用于识别背离。 有一种观点认为,根据计算周期,它可以满足短线交易的要求(周期 6-14),而当周期大于 20 时,它可以用作趋势指标,通过它可以清楚地识别趋势末端。 如果我们假设趋势包含三个连续冲量的思路是正确的(波浪行情理论),那么冲量原理确实可以帮助识别趋势的末段。 也许需要对指标运作进行更全面的分析。 

ADX

方向走势指数(DMI)的概念是由 Wells Wilder 于 1978 年在他的著作《技术交易系统中的新概念》中提出的。 这就是开发该工具背后的思路。

ADX 基于其他两个指标计算:正向(+DI)和负向(-DI),并参考了平均真实范围(ATR)。

ADX=(MAn(+DI--DI)/(+DI+-DI))*100

其中: 

  • +DI — 正向指数 
  • -DI  — 负向指数
  • MASMA (移动均线)
  • n — 均线计算周期 

该公式以简化形式显示。 详细说明于此处提供。

该指标有很多条曲线,而 ADX 主线并未指明趋势方向。 因此,该指标似乎不适合我们。

  

图例 32

这是一个错误的假设。 该指标可以按多种方式运用。 第一个:在价格方向和行情活动之间定义背离。 因此,如果价格继续下跌且 ADX 下跌,则表明存在背离。


图例 33

可以将该方法添加到我们的收藏中。 该方法的复杂性与方向判断相关联。 解决方案之一就是对价格序列走势进行初步评估。 即,我们要分析下降波谷或上升波峰的顺序。 如果最近的峰值低于前一个峰值,而最近的谷值高于前一个谷值,反之亦然,即所谓的内部和外部柱线(与价格行为有关的术语),则可能会出现问题。

  

图例 34

第二种方法是使用 +DI 和 -DI 曲线。 不要忘记 – DI 峰值始终对应于价格图表中的低谷。 在上行趋势中(+DI 高于 -DI),我们使用 +DI 线检查波峰,以便发现经典熊市背离,或使用 -DI 波峰来搜索隐藏的牛市背离。 在下行趋势中(+DI 低于 -DI),分析 -DI 峰值以便搜索经典牛市背离,而 +DI 峰值以便寻找隐藏的空头背离。


图例 35

我认为最有效的是第三种方法:上述两种方法一起应用。 此选项解决了很多问题。 它能够在 ADX 线上找到背离,而不会因等待逆转而造成延迟。 信号应根据总体趋势按类型进行过滤,且无需使用其他工具。

在此,我愿意完成有关经典振荡器的部分。 为什么我们不考虑 AO、AC、TRIX、WPR 和其他类似的指标呢?

分析要选择具有原始计算公式的指标。

WPR(10) 与随机(Stochastic)指标(10.1.1 (最低价/最高价))相同,标尺倒置。 随机指标的范围是 0-100,WPR 的范围是 100-0。


图例 36

动量振荡器(AO)与 MACD(5.35.1 中位价) 相似。 唯一的不同是,使用 SMA(简单平均)对 AO 进行平滑,而在 MACD 中则用 EMA(指数平均),因此速度更快一点。 从下图可以看出,这不会在信号形式上产生重大变化。


图例 37

加速器类似于 OsMA(5.34.5 中位价),与MACD和AO相同。


图例 38

TRIX 基于移动平均线,通过选择 MACD 参数可以达到相同的结果。

  

图例 39

 

交易量(Volumes) 

海量的各式策略要用到技术分析。 使用交易量的策略应包含在一个单独的分组。 这个分组规模较小。 我认为,外汇市场上运用交易量并未达到其应有的水平。 即使外汇市场上没有实际交易量(只有即时报价交易量)。 将有单独的有关交易量的资料。 现在我们在关联背离的情况下考虑它们。

MetaTrader 5 终端标准软件包中只有很少的指标在其算法中用到交易量。 其中包括吸筹/派发(Mark Chaikin),资金流指数(由于公式相似,也可称为交易量 RSI),能量潮(Joseph Granville),市场灵活指数(Bill Williams)和交易量。 Alexander Elder 创立的外汇指数也属于这一类,尽管它被包含在“振荡器”部分中。 这种类型的工具很少,因此在分析交易量背离时,我们经常会遇到以下情况:

  

图例 40

从上图可见,该方法在使用历史数据分析行情时效果很好,但是很难创建自动化工具。 这种方法有很多缺点。 这包括不同时段交易的交易量差异,以及相应的失真。 我们知道亚洲时段的交易量要少于欧洲和美洲时段的交易量。 趋势开始时,以及交易者成交平仓时都会出现尖峰。 后者的交易量可能更大。

  

图例 41

新闻发布可能会伴随着交易量激增。

  

图例 42

用其他任何带有均衡线的指标代替“交易量”,可以部分解决此任务。 交易量的 SMA 可能涵盖一定期间。 这可令您过滤掉一些次要的数值。 这样的指标之一是 BetterVolume。


图例 43

解决问题的另一种方法是将价格范围和交易量指标结合起来。 我们来定义形成新“高点”(“低点”)时烛条的交易量,并进行比较。 我们根据自有算法编辑经典变体。

直方图将含有五种颜色,而非两种。

#property indicator_type1   DRAW_COLOR_HISTOGRAM
#property indicator_color1  Green,Red,Blue,Magenta,Gray


  1. 绿色 - 如果 low[i]>low[i-1] 且 high[i]>high[i-1].
  2. 红色     - 如果 low[i]<low[i-1] 且 high[i]<high[i-1].
  3. 蓝色   - 外侧向上柱线
  4. 粉色 - 外侧向下柱线
  5. 灰色 - 以上都不是 

主计算模块与标准“交易量”指表没有区别。 此外,CalculateVolume 函数还包含直方图柱线的颜色

void CalculateVolume(const int nPosition,
                     const int nRatesCount,
                     const long &SrcBuffer[],
                     const double &h[],
                     const double &l[],
                     const double &o[],
                     const double &c[])
  {
   ExtVolumesBuffer[0]=(double)SrcBuffer[0];
   ExtColorsBuffer[0]=0.0;
//---
   for(int i=nPosition;i<nRatesCount && !IsStopped();i++)
     {
      //--- calculate indicator color
      ExtVolumesBuffer[i]=(double)SrcBuffer[i];
      ExtColorsBuffer[i]=4.0;
      //--- uptrend, UP bar ----
      if(h[i]>h[i-1] && l[i]>l[i-1]&& o[i]<c[i])ExtColorsBuffer[i]=0.0;
      //--- uptrend, DN bar ----
      if(h[i]>h[i-1] && l[i]>l[i-1]&& o[i]>c[i])ExtColorsBuffer[i]=3.0;
      //--- downtrend, DN bar ----
      if(h[i]<h[i-1] && l[i]<l[i-1]&& o[i]>c[i])ExtColorsBuffer[i]=1.0;
      //--- downtrend, UP bar ----
      if(h[i]<h[i-1] && l[i]<l[i-1]&& o[i]<c[i])ExtColorsBuffer[i]=2.0;
      //--- outside UP bar ----
      if(h[i]>h[i-1] && l[i]<l[i-1] && o[i]<c[i])ExtColorsBuffer[i]=2.0;
      //--- outside DN bar ----
      if(h[i]>h[i-1] && l[i]<l[i-1] && o[i]>c[i])ExtColorsBuffer[i]=3.0;
      //--- inside bar ----
      if(h[i]<h[i-1] && l[i]>l[i-1])ExtColorsBuffer[i]=4.0;
     }
//---
  }
//+------------------------------------------------------------------+


图例 44 

尽管此变种不尽完美,但它简化了分析。 可以提供更多的选择,直到计算原理大范围改变。 但请不要忘记,有时候老办法就是最好的方法。 如果更早思路依旧未普及,那么我们不会考虑它们。 毫无疑问,使用该指标可以帮助我们自动进行背离检测。 我们来专注于流行的思路。

资金流指数(Money Flow Index) 

如前所述,计算公式类似于 RSI。

价格=(最高价+最低价+收盘价)/3

MF=价格*交易量

MR=正向MF/负向MF

MFI=100-100/(1+MR)

我认为,它比 RSI 更适合识别超买/超卖区域,因为超卖/超买状态的思路并非意味着价格变化的大小覆盖计算周期,而是此过程中参与者的数量。 而这正是 MFI 所做的。 结果,它能更好地反映因果关系。 然而,它也有相同的缺点。


图例 45

  能量潮(On Balance Volume)

(Joseph Granville)

如果当前收盘价高于前一个收盘价:

OBVn=OBVn-1-Volumen

如果当前收盘价低于前一个收盘价:

OBVn=OBVn-1-Volumen

如果当前收盘价等于前一个收盘价:

OBVn=OBVn-1

其中:

  • OBVn — 当前周期的能量潮指标值;
  • OBVn-1 — 前一周期的能量潮指标值;
  • Volumen — 当前柱线交易量。

参考文献很少提供有关该指标的信息。 但是,它们提供了关键思路: OBV 变化先于价格变化。 因此,我们可以利用价格走势和交易量之间的背离。


图例 46

上图中的背离之一用问号标记。 行情走势波澜不起,主要因素是要过渡到新的一天,而亚洲市场预计不会出现大幅波动。 稍后,目标级别将展示这种波动是有效的。

推力指数

(Alexander Elder).

Force Index=Volume*(CLOSEn-CLOSEn-1)

原始公式与终端中实现的公式有所不同。

Force Index=Volume*(MAn-MAn-1)

对于我来说,根本原因还不是很清楚,但是它并没有提供明显的信号形状变化,这对于我们的目的是完全可以接受的。


图例 47 

此指标生成的其他信号的各个方面,以及它们之间的区别超出了本文的范围。

如前所述,该指标已被指派为振荡器类别,尽管 Alexander Elder 在他的书中写道:“我认为它是衡量市场交易量的最佳工具” 。 

此外,Elder 还使用此工具搜索背离。


图例 48

入场和目标

经典入场规则如下:

在识别出背离之后,在烛条的高点放置突破买入订单,这是形成看涨背离形态的最后一个;对于看跌背离,在最后一根烛条的低点设置突破卖出订单。


图例 49

为能获取最大程度利润而言,该选项可被认为是最佳选择。 于此方法中,可以在 “轨道线(26)” 指标的上边界入场交易(根据行情波动选择偏差)。


图例 50

备选,基于背离形成点构建的等距通道的边界入场,其中第三点是第一点和第二点之间的高(低)点。


图例 51

止损设置为低于做多价的最低价,或高于做空价的最高价。 但是,这种“理想”方法仅适用于满足所有规则,以及其他确认要求的理想形态。 它也适用于较大的时间帧,在该时间帧内可以额外分析行情状态,并适时离场。


图例 52

在交易开始之前很难确定这种浮利的止盈。 价位可以随时间变化。 欠缺之一:计算成交的可能结果非常困难。 在这种情况下,可以使用更可靠的变体。 我们来创建一条趋势线。 成交将在突破趋势线之后入场,其可作为趋势变化信号和额外确认。 在大多数情况下,它几乎等于经典变体价位,但会提供更多的信心。


图例 53

我们可以使用第一部分中的规则,并绘制相应的线条。 有时,指标创建的线条需要调整。

在此类成交中,目标设定在支撑/阻力位。


图例 54

至于双重和三重背离,可以在第一次信号形成结束时设置目标(通常情况)。 更罕见的情况是可能在第一个背离形成点之间,或其开始的位置使用分形。


图例 55

是否总要设置止损价位? 当然,每个人都会选择自己的交易风格和资金管理规则。 仅对于经验丰富的交易者,建议完全不设止损价位,或将止损价位设置得很远。 这样的交易者必须对相关的技术分析和指标充满信心,并且能够即时调整其操作,例如等到成交失控时,手工修改成交,或将亏损成交平仓。

创建交易工具

我们的目的不是批驳现有规则。 我们需要重新分析可用信息,并得出适用的结论。 每个创建交易工具的作者都旨在实现一定的预期结果。 该指标通常是针对特定行情而创建的。 有时其基本思路不是很清楚。 常常,只有作者才能理解信号细节的解读。

交易者可能会尝试在其他条件下应用该指标,从而丧失常规思路和潜在利润。 这就是为什么交易者经常遇到交易机器人稳定亏损的原因。 如果我们改变交易方向会怎样? 它会变成稳定盈利吗?

我们的目标是相似的:如果怎么样。 与该方法有关的一些结果已在第一部分中发表。 现在,我们需要在不同的方面进行实施。 我们使用带有缺点的工具,但在某些条件下仍能提供良好的结果,而其他工具则无法实现这一结果。 这是 ADX 指标。 我们都知道它的缺点。 由于双重平滑,它是滞后的。 其主线以及其他指标线的方向与行情走势方向不一致。 由此,在解释指标时会出现困难。 作者想展示强度而非方向。


图例 56


图例 57

由此,DI+ 似乎没问题,而 DI- 则上下颠倒了。 此指标线的峰值与价格波谷相吻合。


图例 58

我不知道 J. Wells Wilder 在抛物线系统的框架内创建这样一个指标的原因。 我可以假设它是为股票市场而创建的,在该市场中进行交易与外汇市场不同。 购买股票通常持股时间很长,以便获取股息,或用于资本化目的。

我们使用此特定功能。 我们需要利用其最好的一面,并尽可能有效地利用它们。 它的最大优点是,通过将正负两个分量分离,可以根据行情趋势(行情强度)检测波峰和波谷。 该解决方案还令您能够了解市场上正在发生的事情。 无论是在下跌的市场中多头对空头的压力,还是在上涨的市场中空头的压力,由于参与者减少导致整体活跃度降低,亦或交易者只是决定喘息一下,以便分析发生的情况 。 我们将走得更远。 根据主指标线的抛物线走势,我们可以轻松地将其变成具有零平衡线的振荡器形式。 这可以通过删除将主值还原为绝对值来完成 ( ADX)。 从以下行删除:

         dTmp=100.0*MathAbs((ExtPDIBuffer[i]-ExtNDIBuffer[i])/dTmp);

MathAbs 函数。

结果就是,我们得到以下指标。


图例 59


图例 60

从上图可以看出,我们的 ADX(我们称其为 ADX_Osc)显示行情方向时表现出色,以此为基础,我们可以在全局范围内寻找背离。 这条线仍然有点滞后。 可以通过初期的行情逆转信号来弥补这一缺点。 它们的确定基于 “DI-” 和 “DI+”。


图例 61

为了更好地理解为什么以这种方式确定 DI-(红线)和价格之间的差值,请再次阅读与 ADX 相关的部分。 从图中我们可以看到:买家的压力在下跌趋势中已经开始,这导致进一步的盘整,并且指标主线已经确认。 但是我们需要一个更严谨的理由来入场做多。 从图例 60 可以看出,行情继续下跌。

可以用于决策的是 DI- 和 DI+ 的“单向”线。 若价格似乎同时在上涨和下跌,那么为什么选择“单向”。 我们知道这不可能发生。 这就是转移。 当所谓的“内孕柱线”出现时,就会出现这种情况。

我们查验一下。 价格行为:“内孕柱线(IB)是坐落于前一根烛条范围内的一组烛条,其最高的最低价和最低的最高价均不超过前一根烛条。 在较高的时间帧内,设置通常看起来像一个三角形。 内孕柱线表示不确定性和行情盘整。 它通常能在趋势行情中找到,它表示突破母烛条后趋势延续。 它通常发生在行情顶部/底部,主要支撑/阻力价位,以及横盘通道。”

我们的案例不适用于此定义。 您可能还记得,我们判断强度而非方向。 所以,我们的定义应该是这样的:“在当前柱线处的多头力度小于前一根柱线,而空头力度大于前一根柱线。 主线形状则无关紧要。”


图例 62

此处,我们仍然保留主体思想:该指标表示行情停止或逆转。 在评估其品质时,我们考虑由 ADX_Osc 线表示的主要趋势方向(强度)。 如果趋势延展,则上涨趋势的 ADX 线值高于前一个值,下跌趋势的 ADX 线值低于上一个值。 这表示盘整(停止价位)。 如果趋势疲软,主线在上涨趋势中递减,而价格在上涨趋势中上涨(背离),那么我们可以预期行情会逆转。 所有这些就是创建指标所需的。

当然,ADX 可以做到更多。 但是我们的任务不是利用所有可能性。

在我们继续之前,这里有一个小的题外话。 前一段时间,我要撰写一篇文章的提议被拒绝了。 有人建议我开一个博客。 但是发表之前,我已经做了很多工作。 文章仅包含对我来说必不可少的摘录。 当时没有人解释说文章必须包含程序代码。 因而我感到很沮丧。 后来,我重拾这个想法,并希望分享我的研究成果。 我又一次失败了。 对这个思路的简单表述不能令版主满意。 这次我决定撰写结果揭晓之前的所有内容。 当然,这种资料不能提供 100% 的细节。 在继续进行最后阶段的研究之前,我将简要述及为什么所获得的结果似乎毫无价值。

在上一篇文章中,我们简要触及了基于图形构造的指标所引起的问题。 这些工具很难进一步分析,因为这无法在适配模式下完成。 它们只能通过肉眼进行分析,这非常耗时。 指标信号很难传递,因此需要将其代码添加到智能交易系统的代码当中。 正确绘制其指标线还存在难题,这会导致错误的入场信号。 这个问题可以解决,但这超出了本文的范畴。

我们可能应该向 MQL 语言开发人员定位此难题:为什么不能创建图形对象作为机器代码库? 为什么我们需要从中传递数据的缓冲区(用于绘图或数据)不能分别属于主图表窗口及其子窗口? 也许有人会写一篇与此主题相关的文章,或者我也许打算自己来做。 基于上述,我们来总结一下初期结果。 我的观点是,我们为非标准方法选择了最合适的指标,该指标能够应对我们的主要任务。 依据分析,我已断定最适合实现且不会令屏幕超负荷的行为时刻。 我们不会避免在指标中使用所有图形结构,因为主要任务不是交易自动化,而是在交易中应用指标的机会。 

请注意,我们并未创建特定的完整概念。 这是未来工作的“初试”。 每个人都可以利用此工具作为实现所需特定功能的基础。 出于此原因,我们仅针对短线趋势实现“非标准方法”,而利用经典解决方案来应对全局信号。  

ADX 的主要代码保持不变。 我们进行一些修改以便将其实现为振荡器。 原出于此,不能简单地通过句柄调用 ADX。 

#property indicator_separate_window
#property indicator_buffers 8
#property indicator_plots   3
#property indicator_type1   DRAW_LINE
#property indicator_color1  LightSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
#property indicator_type2   DRAW_LINE
#property indicator_color2  Green
#property indicator_style2  STYLE_DOT
#property indicator_width2  1
#property indicator_type3   DRAW_LINE
#property indicator_color3  Red
#property indicator_style3  STYLE_DOT
#property indicator_width3  1
#property indicator_label1  "ADX"
#property indicator_label2  "+DI"
#property indicator_label3  "-DI"
//--- input parameters
input int InpPeriodADX=14; // Period
input int extremum=100; // Extremum (<1 Div= OFF)
input int Gep=4; // Point to Gep
input int Bars_Calculated=300;
//--- global variables
input bool   allLine=false;// All Line
int    ExtADXPeriod;
double PDI,NDI,pDI,nDI;
string short_name="";
int    wid=-1;
//---- buffers
double    ExtADXBuffer[];
double    ExtPDIBuffer[];
double    ExtNDIBuffer[];
double    ExtPDBuffer[];
double    ExtNDBuffer[];
double    ExtTmpBuffer[];
double    ExtUpBuffer[];
double    ExtDnBuffer[];

一些输入需要解释。

input int extremum=100; // Extremum (<1 Div= OFF)


这是极值指标线的数量,我们将对其进行检查以便发现背离。 最小数量为 “1”。 如果更少,则不会执行任何计算。 稍后,在确定最佳数量之后,最好将其设置为全局参数。

input bool   allLine=false;// All Line

此参数允许在屏幕上显示指标操作期间发现的所有背离的指示线,并由 “extremum” 参数定义。 专门设置以便简化指标分析,并判断上述参数的值。


图例 63


图例 64

input int Gep=4; // Point to Gep

它用于美化目的。 数值扩散的点数,由该参数确定,将排布为一条指示线。 我将该值确定为一半到两个点差。 它不会影响缩进。 如果您需要偏移量,则应另外设置该值。 点位将在后面说明。 为了减少 OnDeinit 函数,我们将使用一条命令删除所有带有前缀(等于指标名称)的数据。 从主屏幕删除大量对象时,MetaTrader 5 终端可能会变慢。 为避免这种情况,我们添加一个强制屏幕重绘。

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,short_name);
   ChartRedraw(0);
  }
//+------------------------------------------------------------------+

它注意到,如果终端长时间未连接,子窗口中的图形对象将保持其绑定,而不是绑定到价格/时间坐标,而是以其最后位置的像素为单位。 因此,在确定首次计算的柱线数量的模块中,我们添加一条命令将其删除。 可能有更好的解决方案,但是我如下解决了这个问题。

   if(prev_calculated>1) start=prev_calculated-1;
   else
     {
      OnDeinit(9);
      start=1;
      ExtPDIBuffer[0]=0.0;
      ExtNDIBuffer[0]=0.0;
      ExtADXBuffer[0]=0.0;
     }


用于判断 DI+ 和 DI- 指示线单向走势的模块已被添加到指标的主要计算函数当中。

//+------------------------------------------------------------------+
//|           Fast divergence calculation                            |
//+------------------------------------------------------------------+
   int bar=start;
   if(prev_calculated<2) bar=start+2;
   if(Bars_Calculated>0)bar=fmax(rates_total-Bars_Calculated,start);
//---
   for(int i=bar;i<rates_total-1 && !IsStopped();i++)
     {
      ExtUpBuffer[i-1]=EMPTY_VALUE;
      ExtDnBuffer[i-1]=EMPTY_VALUE;
      //---
      color clrUp=clrLime;
      color clrDn=clrDarkViolet;
      //---
      if((ExtPDIBuffer[i-1]<ExtPDIBuffer[i-2] && ExtNDIBuffer[i-1]<ExtNDIBuffer[i-2]) || 
         (ExtPDIBuffer[i-1]>ExtPDIBuffer[i-2] && ExtNDIBuffer[i-1]>ExtNDIBuffer[i-2]))
        {
         if(ExtPDIBuffer[i-1]>ExtNDIBuffer[i-1])
           {
            if(ExtADXBuffer[i-1]>ExtADXBuffer[i-2])
               ExtUpBuffer[i-1]=high[i-1];
            else
              {
               ExtUpBuffer[i-1]=EMPTY_VALUE;
               ExtDnBuffer[i-1]=low[i-1];
               clrDn=clrGold;
              }

            //---
            if(MathAbs(ExtUpBuffer[i-1]-ExtUpBuffer[i-2])<Gep*_Point)
               ExtUpBuffer[i-1]=ExtUpBuffer[i-2];
            if(MathAbs(ExtDnBuffer[i-1]-ExtDnBuffer[i-2])<Gep*_Point)
               ExtDnBuffer[i-1]=ExtDnBuffer[i-2];
            //---
           }
         if(ExtPDIBuffer[i-1]<ExtNDIBuffer[i-1])
           {
            if(ExtADXBuffer[i-1]<ExtADXBuffer[i-2])
               ExtDnBuffer[i-1]=low[i-1];
            else
              {
               ExtDnBuffer[i-1]=EMPTY_VALUE;
               ExtUpBuffer[i-1]=high[i-1];
               clrUp=clrBlue;
              }

            //---
            if(MathAbs(ExtDnBuffer[i-1]-ExtDnBuffer[i-2])<Gep*_Point)
               ExtDnBuffer[i-1]=ExtDnBuffer[i-2];
            if(MathAbs(ExtUpBuffer[i-1]-ExtUpBuffer[i-2])<Gep*_Point)
               ExtUpBuffer[i-1]=ExtUpBuffer[i-2];
            //---
           }
        }
      //---
      if(ExtUpBuffer[i-1]==EMPTY_VALUE)
         ExtUpBuffer[i-1]=ExtUpBuffer[i-2];
      if(ExtDnBuffer[i-1]==EMPTY_VALUE)
         ExtDnBuffer[i-1]=ExtDnBuffer[i-2];
      //---
      if(ExtUpBuffer[i-1]!=EMPTY_VALUE)
        {
         ArrowCreate(short_name+(string)time[i]+(string)Lime,time[i],ExtUpBuffer[i-1],ANCHOR_BOTTOM,clrUp);
         if(ExtUpBuffer[i-1]!=ExtUpBuffer[i-2])
            ArrowCreate(short_name+(string)time[i-1]+(string)Lime,time[i-1],ExtUpBuffer[i-1],ANCHOR_BOTTOM,clrUp);
        }
      else
         ArrowCreate(short_name+(string)time[i]+(string)Lime,time[i],ExtUpBuffer[i-2],ANCHOR_BOTTOM,clrUp);
      //---
      if(ExtDnBuffer[i-1]!=EMPTY_VALUE)
        {
         ArrowCreate(short_name+(string)time[i]+(string)Red,time[i],ExtDnBuffer[i-1],ANCHOR_TOP,clrDn);
         if(ExtDnBuffer[i-1]!=ExtDnBuffer[i-2])
            ArrowCreate(short_name+(string)time[i-1]+(string)Red,time[i-1],ExtDnBuffer[i-1],ANCHOR_TOP,clrDn);
        }
      else
         ArrowCreate(short_name+(string)time[i]+(string)Red,time[i],ExtDnBuffer[i-2],ANCHOR_TOP,clrDn);
     }

此外,这里还添加了用于启动全局背离计算函数的模块。

//+-------------------- Finding a discrepancy ----------------------+
   bar=start;
   if(bar>rates_total-2)bar=rates_total-2;
   if(Bars_Calculated>0)bar=fmax(rates_total-Bars_Calculated,bar);
   for(int i=bar;i<rates_total-2 && !IsStopped() && extremum>0;i++)
     {
      UP(i,ExtADXBuffer,high,time);
      DN(i,ExtADXBuffer,low,time);
     }

第一部分中的指标已从 MQL4 重写。 该版本最初是用 MQL5 编写的,这就是为什么背离搜索已更改的原因。

空头背离搜索函数。

//+----------- Detecting UP divergences ------------------------------+
void UP(int l,const double &buf[],const double &high[],const datetime &time[])
  {
   if(Extremum(buf[l+1],buf[l],buf[l-1])<0)
     {
      int i=l;
      for(int j=0;j<extremum;j++)
        {
         int counted=LastPeak(i,buf);
         if(counted!=-1)
           {
            if(buf[l]<buf[counted] && high[l]>high[counted])
              {
               double k=fabs(buf[l]-buf[counted])/(l-counted);
               int z=1;
               bool yes=true;
               for(i=l-1;i>counted;z++,i--)
                     if(buf[i]>buf[l]+k*z){yes=false;break;}
               if(yes)
                 {
                  DrawPriceTrendLine(time[l],time[counted],high[l],high[counted],Red,STYLE_SOLID);
                  DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Red,STYLE_SOLID);
                  break;
                 }
              }

            if(buf[l]>buf[counted] && high[l]<high[counted])
              {
               double k=fabs(buf[l]-buf[counted])/(l-counted);
               int z=1;
               bool yes=true;
               for(i=l-1;i>counted;z++,i--)
                     if(buf[i]>buf[l]-k*z){yes=false;break;}
               if(yes)
                 {
                  DrawPriceTrendLine(time[l],time[counted],high[l],high[counted],Red,STYLE_DOT);
                  DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Red,STYLE_DOT);
                  break;
                 }
              }
           }
         i=counted;
        }
      //---
     }
  }

多头背离搜索函数。

//+----------- Detecting DN divergences ------------------------------+
void DN(int l,const double &buf[],const double &low[],const datetime &time[])
  {
   if(Extremum(buf[l+1],buf[l],buf[l-1])>0)
     {
      int i=l;
      //---
      for(int j=0;j<extremum;j++)
        {
         int counted=LastTrough(i,buf);
         if(counted!=-1)
           {
            if(buf[l]>buf[counted] && low[l]<low[counted])
              {
               double k=fabs(buf[l]-buf[counted])/(l-counted);
               int z=1;
               bool yes=true;
               for(i=l-1;i>counted;z++,i--)
                     if(buf[i]<buf[l]-k*z){yes=false;break;}
               if(yes)
                 {
                  DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Green,STYLE_SOLID);
                  DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Green,STYLE_SOLID);
                  break;
                 }
              }
            if(buf[l]<buf[counted] && low[l]>low[counted])
              {
               double k=fabs(buf[l]-buf[counted])/(l-counted);
               int z=1;
               bool yes=true;
               for(i=l-1;i>counted;z++,i--)
                     if(buf[i]<buf[l]+k*z){yes=false;break;}
               if(yes)
                 {
                  DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Green,STYLE_DOT);
                  DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Green,STYLE_DOT);
                  break;
                 }
              }
           }
         i=counted;
        }
      //---
     }
  }

主要区别在于附加了过滤器。 我发现对于图例 20 和 28 的情况,信号的正向趋势小于 30%。 这就是为什么要将它们剔除。 过滤器代码高亮显示。 极值检测函数也已更新。 排除了按指标线位置的正负值进行过滤。 对我们而言,这无大用,甚至可能是有害的。 由于该行在当前和上一根柱线上可以取得相等的数值,使之能够提供主定义等于零。 

如有必要,以后可以轻松地更改搜索规则。

//+-- Search for extrema --------------------------------------------+
int Extremum(double a,double b,double c)
  {
   if((a-b)*(b-c)<=0)
     {
      if(c>b) return(1); //DN extremum
      if(c<b) return(-1);//UP extremum
     }
   return(0);
  }

搜索左肩几乎没有变化。

//+----- Search for the second UP extremum --------------------------+
int LastPeak(int l,const double &buf[])
  {
   for(int i=l-2; i>4; i--)
     {
      int ext=Extremum(buf[i+1],buf[i],buf[i-1]);
      if(ext < 0)return (i);
     }
   return (-1);
  }
//+----- Search for the second DN extremum --------------------------+
int LastTrough(int l,const double &buf[])
  {
   for(int i=l-2; i>4; i--)
     {
      int ext=Extremum(buf[i+1],buf[i],buf[i-1]);
      if(ext > 0)return (i);

     }
   return (-1);
  }

以下函数构建了前面提到的要点。 这些点位标记短线背离。

//+-------------------- Creates an arrow -----------------------------+ 
bool ArrowCreate(string                  name,
                 datetime                time,
                 double                  price,
                 ENUM_ARROW_ANCHOR       anchor,
                 color                   clr)
  {
//--- reset the error value 
   ResetLastError();
//--- create an arrow 
   if(!ObjectCreate(0,name,OBJ_ARROW,0,time,price))
     {
      Print(__FUNCTION__,
            ": failed to create an arrow! Error code = ",GetLastError());
      return(false);
     }
   ObjectSetInteger(0,name,OBJPROP_ARROWCODE,167);
//--- set the binding type 
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
   ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
   ObjectSetInteger(0,name,OBJPROP_BACK,false);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_SELECTED,false);
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
//--- successful implementation 
   return(true);
  }
//+------------------------------------------------------------------+ 


主要的绘图模块也一并进行了更新,以便能显示所有背离指标线,或仅显示 “ extremum” 参数指定间隔内的最后一条线。

对于主图表窗口

//+------ Creating objects on the price chart -----------------------+
void DrawPriceTrendLine(datetime T_0,datetime T_1,double P_0,double P_1,color color_0,int style)
  {
   string name_0=short_name+"Line_Sn"+ColorToString(color_0);
   string name_1="";
   if(allLine)
      name_1=short_name+DoubleToString(T_0,0);
   else
      name_1=short_name+DoubleToString(T_1,0);
//--- 
   ObjectDelete(0,name_1);
   drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,0,true,false,0);
//+-----------+
   if(style==STYLE_DOT)
     {
      ObjectDelete(0,name_0);
      drawLineS(name_0,T_1,T_0,P_1,P_0,clrAqua,0,3,true,true,0);
     }
  }

以及在指标窗口

//+------ Creating objects in the indicator window ------------------+
void DrawIndicatorTrendLine(datetime T_0,datetime T_1,double P_0,double P_1,color color_0,int style)
  {

   int window=wid;
   string name_0=short_name+"Line_Pn"+ColorToString(color_0);
   string name_1="";
   if(allLine)
      name_1=short_name+DoubleToString(T_0+wid,0);
   else
      name_1=short_name+DoubleToString(T_1+wid,0);
//---
   ObjectDelete(0,name_1);
   drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,0,false,false,window);
//---
   if(style==STYLE_SOLID)
     {
      ObjectDelete(0,name_0);
      drawLineS(name_0,T_1,T_0,P_1,P_0,clrMagenta,style,2,true,true,window);
     }
  }

出于同样的原因,删除命令从趋势线构造函数搬到主模块。

//+------------------------------------------------------------------+
void drawLineS(string name,datetime T_0,datetime T_1,double P_0,double P_1,color clr,
               int style,int width,bool back,bool ray,int window)
  {
   ObjectCreate(0,name,OBJ_TREND,window,T_0,P_0,T_1,P_1,0,0);
   ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,ray);
   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_STYLE,style);
   ObjectSetInteger(0,name,OBJPROP_WIDTH,width);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_BACK,back);
  }

该指标现在如下所示。


图例 65

除了常见的背离线外,我们还看到许多标记合并区域的点位,它们是做空做多交易的入场点。 这些信号按揭示的规则(DI+ 和 DI- 的单向走势)来判定。 绿色点位显示做多入场点,紫色点位显示做空的入场点。 在绿色按钮背景下出现蓝点,或在紫色背景下出现黄点,表示趋势不确定或可能发生了变化。 成交开立后,这些点位可以用作尾随止损的价位。 请注意,您基于这些点位挂单入场不可取。 首先,这些点位只是识别出短线行情趋势,并可能导致假信号。 当烛条收盘价高于或低于此水平时,生成交易信号。 Gap 变量用于绘图。 该算法如下:出现做空信号后,在形成信号的柱线最低价下方出现一个点。 对于做多信号,在最高价上方绘制一个点。 最高价/最低价的缩进由确定锚点 ANCHOR_BOTTOMANCHOR_TOP 的函数实现。 之后,将基于第一个点位创建 "+\- Gap" 范围内的所有信号。

此版本可以进一步更改。 例如,您可以尝试减少主线滞后。 最简单的解决方案是减少第二个平滑周期,并将其改为变量。 我们还可以删除涉及经典信号检测的部分,并添加前面提到的与 MACD 有关的算法。 图表上只会显示入场价位。 所以,我们剔除了不必要的绘图动作。

我们可以通过创建一个小型机器人来检测这些思路。 我们对经典变体和主线方向不感兴趣。 这令我们可以使用来自终端的标准 ADX。 仅当突破烛条太多时才应用过滤器。 若是没有相反条件的通道线可作为设置止损的情况,则引入止损距离。 另外,在 EA 中,我们需要设置与最高价/最低低的距离。 以下是主要货币对的测试结果:欧元/美元,英镑/美元,美元/日元,H1 和 H4 时间帧内,覆盖 2016 年 1 月 1 日至 2019 年 1 月 6 日。

EURUSD Н1


EURUSD Н4


GBPUSD H1


GBPUSD H4


JPYUSD H1


JPYUSD H4


当然效果不是很好。 但这不是目标。 更重要的是,有积极的趋势。

结束语

那么,对于著名思路有什么新的处理方法呢? 是浪费时间还是有所进步? 您是一名成功的交易者。 您有很出色的操作策略。 您是否应该修改策略,以便获得更佳的效果? 或原样保留? 您应该自行决定。 也许我的研究结果会激发人们反思自己的策略,甚至创建全新的技术分析工具。

我是一个自学成才的人,所以我始终认为公开可用的资料至关重要。 我不追捧热门作者的具体观点。 在不同的论坛上,我阅读了大量由其作者提供的,有关策略细微差别的详尽论述。 我始终尝试在利润最大化概念的框架内找到最有效的解决方案。 我希望这些资料能够对读者有所帮助,并鼓励他们使用新的方法来改善他们的策略。 该资料仅包括研究背离时所做的一小部分。 我在研究过程中出现的一些难题需要非标准的解决方案。 这很难在一篇文章中阐述所有内容。 因此,可能我将发布更多阐述其他非标准解决方案的资料。

附言:请不要提出改进已发表资料或创建交易机器人的要求。 请到自由职业者服务板块发布任务。 编程对我来说是很有必要的:我开始开发只是为了学习语言的可能性,并检验我的思路。

#      名称         类型                           说明                      
1 ADX_Osc.mq5 指标  背离分析指标。 
2 TestADX.mql5 智能系统  用于验证思路的智能交易系统。 

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/5703

附加的文件 |
ADX.zip (149.51 KB)
优化管理(第二部分):创建按键对象和附加逻辑 优化管理(第二部分):创建按键对象和附加逻辑

这篇文章是之前发表的关于创建优化管理图形界面的延续,本文探讨了附加组件的逻辑,将为 MetaTrader 5 终端创建一个包装器:它将使附加组件通过C#作为一个托管进程运行。此外,本文还探讨了对配置文件和安装文件的操作。应用逻辑分为两部分:第一部分描述了按下特定按键后调用的方法,第二部分描述了优化启动和管理。

美林(Merrill)形态 美林(Merrill)形态

在本文中,我们将研究美林形态的模型,并尝试评估它们与当前行情的相关性。 为此,我们将开发一种工具来测试形态,并将其模型应用在各种数据类型,例如收盘价、最高价和最低价,以及震荡指标。

轻松快捷开发 MetaTrader 程序的函数库(第十五部分):品种对象集合 轻松快捷开发 MetaTrader 程序的函数库(第十五部分):品种对象集合

在本文中,我们将研究基于上一篇文章中所开发的抽象品种对象来创建品种集合。 抽象品种的后代会阐明品种数据,并在程序中定义基本品种对象属性的可用性。 此类品种对象应按其隶属的分组关系加以区分。

轻松快捷开发 MetaTrader 程序的函数库 (第十六部分) : 品种集合事件 轻松快捷开发 MetaTrader 程序的函数库 (第十六部分) : 品种集合事件

在本文中,我们将为所有函数库的对象创建一个新的基类,在其所有衍生类中加入事件功能,并基于新的基类开发用来跟踪品种集合事件的类。 我们还将修改帐户和帐户事件类,以便开发新的基本对象功能。