English Русский Español Deutsch 日本語
preview
您应当知道的 MQL5 向导技术(第 44 部分):平均真实范围(ATR)技术指标

您应当知道的 MQL5 向导技术(第 44 部分):平均真实范围(ATR)技术指标

MetaTrader 5测试者 |
55 0
Stephen Njuki
Stephen Njuki

概述

平均真实范围是一款常见且流行的波动率指标,对于外汇交易者而言,它“最接近”交易量数据。作为一款指标而开发,其意在跟踪价格柱线范围,而忽略柱线内的价格变化,它已成为该行业的中坚力量,不仅用于过滤入场信号,还用于指导仓位规模。我们通过将指标分解为可能的形态来考察该指标,就如我们在之前指标文章中所做的那样,也许主要区别在于,我们所考察形态除了自定义信号类之外,还针对由向导汇编的智能系统的自定义资金管理类。

不过,在我们开始之前,我们先要把上次开始的 ADX 指标圆满完结。


ADX 逆转

ADX 的形态-6 是逆转,其特征是在显见趋势结束时 ADX 的主缓冲区下降。简要回顾 ADX,它衡量趋势的强度,振荡器主缓冲区的峰值或上升,表明当下趋势的强度。此外,还有 2 个额外的缓冲区,DI+ 和 DI-,它们也分别量化了价格上涨和价格下跌的强度。

故此,看涨信号的标志是,已持续一段时间的强劲看跌趋势,加上主振荡指标缓冲区的读数在大约 2 – 3 根价格柱线上,从 50 水平上方下降到 40 水平下方。这背后的论调是,由于 ADX 衡量趋势强度,当前趋势正在减弱,因此它即将逆转,在这种情况下是看涨趋势,即将站稳脚跟。相较之,看跌信号的标志是,强劲看涨趋势减弱 ,ADX 主缓冲区相似地从高位下降至 40 下方。我们在信号类中实现这一点,如下所示:

//+------------------------------------------------------------------+
//| Check for Pattern 6.                                             |
//+------------------------------------------------------------------+
bool CSignalADX::IsPattern_6(ENUM_POSITION_TYPE T)
{  if(Base(X()+3) >= 50 && Base(X()) <= 40)
   {  if(T == POSITION_TYPE_BUY && Close(StartIndex()) > Close(StartIndex() + m_ma_period))
      {  return(true);
      }
      else if(T == POSITION_TYPE_SELL && Close(StartIndex()) < Close(StartIndex() + m_ma_period))
      {  return(true);
      }
   }
   return(false);
}

为输入参数 'Patterns Used' 分配整数值 64 来专门测试该形态,得到以下结果:

adx_r6


ADX 和支撑/阻力突破

形态-7 是我们正在研究的 ADX 形态的第 8 个,也是倒数第二个,它结合了 ADX 主缓冲区中的峰值、与支撑位或阻力位的突破。因为在代码中解析支撑和阻力线比在手工交易中更成问题,所以我们将依靠第二个指标,即布林带,来更好地辅助定义它们。在最近关于 RSI 和布林带的文章中,我曾研究过更细微的变通之法,欢迎读者去看看它们,重新审视我们此处选用的含义。

我们的支撑和阻力突破将简单地依照刺穿布林带指标的上、下轨来标记。因此,看涨信号的标志是 ADX 主缓冲区上升至 25 水平上方,而价格飙升刺穿布林带上轨,而看跌信号的标志是 ADX 也类似上涨,而价格跌破布林带下轨。我们的 MQL5 实现如下:

//+------------------------------------------------------------------+
//| Check for Pattern 7.                                             |
//+------------------------------------------------------------------+
bool CSignalADX::IsPattern_7(ENUM_POSITION_TYPE T)
{  if(Base(X()+2) < 25 && Base(X()) > 25)
   {  if(T == POSITION_TYPE_BUY && Close(StartIndex()) >= Upper(StartIndex()))
      {  return(true);
      }
      else if(T == POSITION_TYPE_SELL && Close(StartIndex()) <= Lower(StartIndex()))
      {  return(true);
      }
   }
   return(false);
}

测试向导汇编的智能系统,将输入参数 “Patterns Used” 设置为 128,即仅用该形态,为我们给出以下结果:

adx_r7


以 RSI 确认的 ADX

我们的最后一个形态-8,结合了 ADX 与我们已考察过的 RSI 指标。由于 ADX 是一个趋势衡量指标,而 RSI 往往用于标记超买和超卖点,因此从 ADX 的立场来看,两者结合要审核上升或主要趋势,而非它们的结局。在这一点上,我们关注 RSI 在 50 水平的交叉,而非它触及了 70/30 的阈值。

因此,看涨信号的标志是 RSI 从低于 50 突破至 50 上方,同时 ADX 主缓冲区从低于 25 升至 25 上方。相较之,看跌信号的标志是 RSI 从 50 水平上方跌至 50 下方,ADX 值再次上推至 25 关口上方。我们的 MQL5 实现如下:

//+------------------------------------------------------------------+
//| Check for Pattern 8.                                             |
//+------------------------------------------------------------------+
bool CSignalADX::IsPattern_8(ENUM_POSITION_TYPE T)
{  if(Base(X()+1) < 25 && Base(X()) > 25)
   {  if(T == POSITION_TYPE_BUY && RSI(StartIndex()) > 50 && RSI(StartIndex() + 1) < 50)
      {  return(true);
      }
      else if(T == POSITION_TYPE_SELL && RSI(StartIndex()) < 50 && RSI(StartIndex() + 1) > 50)
      {  return(true);
      }
   }
   return(false);
}

测试该形态,在形态输入整数里赋值 256,为我们给出以下结果:

adx_r8


理想 ADX 形态的优化

由向导汇编的智能系统,此处此处的指南文章都有关于如何依照本文末尾附带的代码完成该操作,也可在我们迄今为止研究过的所有 ADX 形态中使用,只是权重不同而已。正如我之前提到的,这不一定是理想的,因为您往往会遇到不同的形态相互抵消,这意味着从优化运行中,大抵会得到 “曲线拟合” 的结果,且很难在样本数据之外复现它们的绩效。据此所述,以下是我们目前研究过的所有 ADX 九种形态的一些组合测试结果。

adx_r_all

adx_c_all


ATR

上面讲述的平均真实范围振荡器指标衡量波动性,这对外汇交易者来说至关重要,因为外汇交易缺乏成交量数据。因此,我们也来看看其形态,其中一些在我们的典型自定义信号类之外也适用。


波动率突破信号

若当前 ATR 值上升显著高于其近期均值,或许指示波动性突破。反过来,这意味着一种交易策略,即 ATR 显著增加时,按突破方向入场交易,是市场可能会在该方向上经历大幅价格走势的信号。补充指标,如移动平均线、MACD 等也能辅助判定交易方向。我们的 MQL5 实现如下:

//+------------------------------------------------------------------+
//| Check for Pattern 0.                                             |
//+------------------------------------------------------------------+
bool CSignalATR::IsPattern_0(ENUM_POSITION_TYPE T)
{  if(ATR(X()) > ATR(X() + 1) && ATR(X() + 1) > ATR(X() + 2) && ATR(X() + 2) > ATR(X() + 3))
   {  if(T == POSITION_TYPE_BUY && Close(X()) > Close(X() + 1) && Close(X() + 1) > Close(X() + 2) && Close(X() + 2) > Close(X() + 3))
      {  return(true);
      }
      else if(T == POSITION_TYPE_SELL && Close(X()) < Close(X() + 1) && Close(X() + 1) < Close(X() + 2) && Close(X() + 2) < Close(X() + 3))
      {  return(true);
      }
   }
   return(false);
}

测试该特定的单独形态,“Used Patterns” 的输入赋值 1,为我们给出以下报告,这是短暂优化后获得的众多有利结果之一。我们正依据 2022 年 H1 时间帧优化 EURUSD 货币对。

tar_r0


突破确认的 ATR 阈值

利用 ATR 作为突破确认的关键,在于 ATR 是一种波动性量值。为覆盖一个设定周期的平均范围(高点减去低点)设定一个值,它可帮助交易者判定每根新柱线的价格波动是多少。当价格移动超出定义的支撑或阻力位时,就发生突破。因此,ATR 通过采用波动率阈值来确认走势,从而作为假突破的过滤器。

突破的一个常见问题是价格或许会短暂突破某个水平,然后回撤。ATR 阈值可填补这些漏洞,如果价格相对于 ATR 值高于/低于特定百分比的关键水平,则可通过确认突破来帮助过滤这一点。举例,如果 ATR 为 20 点,若价格超出支撑/阻力位至少 1.5 倍或 2 倍(如果超过 20 点),那么或许认为突破有效,如此表明是真正的动量变化,而非噪音。因此,这些 ATR 读数必然非常敏感,这就是为什么应对更快的市场或短期策略,要设置较低的 ATR 周期(例如,7 或 10,而非典型值 14),从而更好地适应波动性。不过,若是波段交易,较长的 ATR 周期(例如 14 或 20)可以消除噪音,并提供更稳定的突破确认信号。

然而,我们的 MQL5 实现采用了一种略有不同的方式,即我们依靠一个绝对 ATR 数值跟踪价格波段。如果特定方向的价格变化,伴随合理的 ATR 移动,即超过优化阈值,则在价格趋向上触发新信号。我们按如下方式编码:

//+------------------------------------------------------------------+
//| Check for Pattern 1.                                             |
//+------------------------------------------------------------------+
bool CSignalATR::IsPattern_1(ENUM_POSITION_TYPE T)
{  if(ATR(X()) >= m_threshold_points*m_symbol.Point())
   {  if(T == POSITION_TYPE_BUY && Close(X()) > Close(X() + 1) && Close(X() + 1) > Close(X() + 2) && Close(X() + 2) > Close(X() + 3))
      {  return(true);
      }
      else if(T == POSITION_TYPE_SELL && Close(X()) < Close(X() + 1) && Close(X() + 1) < Close(X() + 2) && Close(X() + 2) < Close(X() + 3))
      {  return(true);
      }
   }
   return(false);
}

仅使用该形态的优化测试运行会得到以下结果:

tar_r1


ATR 作为退出信号

ATR 的市场波动性量值,令其成为基于当前市场条件判定动态离场点的有效工具。不同于固定点数或点位离场策略,基于 ATR 的离场可适应市场波动性,确保离场发生在有意义的水平,而非随意的阈值。ATR 值的突增可能表明重大市场事件(美联储会议纪要、等等),或潜在的逆转。因此,当 ATR 扩张超过某个阈值时,标志波动性加剧,可能导致趋势耗尽或逆转,此时交易者可以选择某些持仓离场。该悬而未决的逆转代表一个信号。

波段交易者通过在最近波段高点或低点上增加或减少 ATR 的倍数,进一步按照 ATR 在关键的已知/已识别价位上离场。这令他们能够参考平均价格走势、并在关键逆转点离场。波段交易者这种基于 ATR 水平的离场形式,降低了不利歧途、或无故回撤的风险,尤其在波动性增加期间,这可能预示着即将到来的逆转、或盘整阶段。

此外,在区间波动的市场中,ATR 趋于低位,因此当 ATR 突然上升时,或许指示潜在的突破、或波动性增加。如果交易者的持仓在该范围内,他们可将该上涨当作离场信号。此处的基本规则是,始终避免低波动性离场,这有助于交易者避免陷入动荡、横盘整理的市场,从而在他们的交易中维持有利的风险/回报状况。不过,我们的 MQL5 实现有点简单,因为我们正在构建一个自定义信号类,并且我们正在寻找入场点。这就是我们如何编写形态-2:

//+------------------------------------------------------------------+
//| Check for Pattern 2.                                             |
//+------------------------------------------------------------------+
bool CSignalATR::IsPattern_2(ENUM_POSITION_TYPE T)
{  if(ATR(X()) >= 2.0 * m_threshold_points*m_symbol.Point())
   {  if(T == POSITION_TYPE_SELL && Close(X()) > Close(X() + 1) && Close(X() + 1) > Close(X() + 2) && Close(X() + 2) > Close(X() + 3))
      {  return(true);
      }
      else if(T == POSITION_TYPE_BUY && Close(X()) < Close(X() + 1) && Close(X() + 1) < Close(X() + 2) && Close(X() + 2) < Close(X() + 3))
      {  return(true);
      }
   }
   return(false);
}

此处我们的方式本质上要求在 ATR 值过高时趋势会逆转,是优化阈值的两倍多。这当然并非利用这一点的最佳方式,正如读者或许已经注意到,我们在上面曾提到离场的“更有趣”途径。不过,如常,可以修改附加的源代码,来得到替代方式。依据 EURCHF 货币对的 2022 年 H1 时间帧运行简短的优化测试,为我们给出以下报告:

atr_r2


波动率收缩信号

ATR 收缩也可作为波动性扩张的准备信号,即暴风雨前的平静。低波动性区间典型情况下在价格飙升、或一场动荡之前来到。一些交易者经常监控 ATR 收缩,以便预测何时可能突破,为即将到来的走势自我备战。在这样的时期之后,ATR 的突然上升往往是已经发生突破的有力证明。因此,一旦波动率再次开始扩大,交易者就可以凭据 ATR 收缩入场交易,从而与趋势保持一致。

ATR 收缩的另一个好处与限时离场有关。一些交易者会在一段时间后平仓离场,故用 ATR 来指导何时把停滞不前的持仓了结,对此非常有助。如果 ATR 较低、或随时间推移而下降,则或许是动量减弱信号,此刻离场是有意义的,因为持仓不再有明显动静。在趋势跟踪策略中,ATR 收缩也能随机应变。在强劲趋势中,如果收缩扎根,则可能是趋势正在失去动力,且或许进入盘整的信号。这可为趋势追随者提供一个为潜在逆做准备、或一些止盈的机会。对于趋势交易者来说,暂时离场或许更有意义。

对于波段交易者来说,ATR 收缩可能是价格陷入盘整阶段的信号,建议此刻平仓离场,避免陷入横盘整理走势。相较之,一旦收缩结束,波段交易者可在波动性再次开始扩大时寻找入场点。再者,波段交易者可用 ATR 收缩来识别区间波动行情,通过在支撑位买入、并在阻力位卖出来进行区间交易,直到发生向上突破或向下击穿。

另外,值得注意的是,尤其是对于不透明的外汇市场,ATR 收缩往往发生在交易量下滑的同时,这通常意味着市场参与者处于优柔寡断。当交易量增加,并且 ATR 扩张时,这可能预示随着新的流动性入场,可能会有所突破。结合 ATR 收缩与随后的成交量激增,对于希望在波动率扩张期间入场的突破交易者来说是一个实用的确认。至于本文,波动率收缩作为捕捉反转、并入场的信号。这些未决逆转过后会定义我们预期的价格方向。如果 ATR 在下行趋势后逐渐减弱,我们预计会出现回调,因此得到一个看涨信号。另一方面,如果 ATR 的下跌发生在牛市末期,我们会将其视为看跌信号。我们的代码如下所示:

//+------------------------------------------------------------------+
//| Check for Pattern 3.                                             |
//+------------------------------------------------------------------+
bool CSignalATR::IsPattern_3(ENUM_POSITION_TYPE T)
{  if(ATR(X()) < ATR(X() + 1) && ATR(X() + 1) < ATR(X() + 2) && ATR(X() + 2) < ATR(X() + 3))
   {  if(T == POSITION_TYPE_SELL && Close(X() + 3) > Close(X() + 4) && Close(X() + 4) > Close(X() + 5) && Close(X() + 5) > Close(X() + 6))
      {  return(true);
      }
      else if(T == POSITION_TYPE_BUY && Close(X() + 3) < Close(X() + 4) && Close(X() + 4) < Close(X() + 5) && Close(X() + 5) < Close(X() + 6))
      {  return(true);
      }
   }
   return(false);
}

仅用形态-3 运行测试,形态输入参数取 8,优化为我们给出以下结果:

atr_r3


ATR 通道((ATR 波带)

ATR 通道(也称 ATR 波带)是基于波动率的动态波带,可取平均真实范围(ATR)的倍数绘制价格的上轨和下轨。就像布林带一样,它们有助于围绕价格创建一个通道,在这种特殊情况下,能有助于反映市场波动。

就像波带一样,这些基于价格波动的扩展和收缩,为交易者提供了给定的时间帧内,价格偏离其平均值多远的典型值。还有,上轨和下轨分别充当动态支撑位和阻力位,如此这般价格往往会在这些波带内扰动,并且触及或突破这些“水平”,可作为潜在逆转或延续的信号。不同于静态支撑/阻力位,这些边界更具动态性,令它们对普遍的市场条件更具响应性。

故此,来自这些波带的信号,如价格突破 ATR 上轨,是表明看涨趋势、或买压增加,而跌破下轨则表明看跌趋势、或抛压。对于手工交易者,必须实现一个自定义指标来物理性绘制这些波带,但在我们的例子中,由于我们使用由向导汇编的智能交易系统(这里这里有为新读者提供的指南),我们不必为此烦恼。鉴于我们正在把我们的交易过程自动化,我们能取价格移动平均线和 ATR 这两个单独的指标读数,并将它们相加,以便在每根新柱线上定义这些波带。我们实现该形态的 MQL5 版本如下:

//+------------------------------------------------------------------+
//| Check for Pattern 4.                                             |
//+------------------------------------------------------------------+
bool CSignalATR::IsPattern_4(ENUM_POSITION_TYPE T)
{  if(T == POSITION_TYPE_BUY && Close(X()) > MA(X()) + 2.0 * ATR(X()))
   {  return(true);
   }
   else if(T == POSITION_TYPE_SELL && Close(X()) < MA(X()) - 2.0 * ATR(X()))
   {  return(true);
   }
   return(false);
}

当与布林带或肯特纳(Keltner)通道等其它指标搭配使用时,这样的波带可承担额外的作用,例如通过确认突破足够重要,来过滤假突破。ATR 通道的其它应用与我们上面提到的有点重叠,不过它们仍值得一提。ATR 通道能有助于识别趋势强度和方向。当价格持续向 ATR 上轨靠拢时,它预示一个强劲看涨趋势。类似地,价格沿下轨移动表明一个强劲的看跌趋势。这种趋势迹象在一些大的时间帧内看似反复拉扯的市场中可以派上用场。相较之,如果价格难以突破 ATR 波轨、或频繁触及波轨而未跟进,这可能是趋势耗尽、或势头减弱的信号。

交易者还用 ATR 波带来识别均值回归机会,尤其是在区间波动的行情中。当价格触及上轨或下轨时,它或许是资产超买或超卖的信号,且可能会朝均值(平均价格)逆转。因此,根据所研判的时间帧,当价格未突破 ATR 波轨的上轨或下轨,而是反弹时,这可能是向交易者发出止盈或逆转持仓的信号。

当使用基于波动率止盈时,这些波轨可以提供基于波动率的动态水平。在 ATR 区间之外设置止盈能有助于保护交易免受正常市场噪音的影响,在波带内为价格波动留出空间,这样将把资金留在桌面上。在我们的形态-4 实现中并未考虑这一点,因为我们正在做一个自定义信号类,其功能会出现在另一个由向导汇编的智能系统的自定义尾随类中。从优化阶段运行测试,其设置类似于我们上面所用的设置;EURCHF,H1 时间帧,2022 年,呈现如下:

atr_r4

然后,我们将所有这些信号合并为一个信号,并配以不同的权重,以下测试结果得自我们的有利优化之一。

atr_r_all

atr_c_all


尾随类中的 ATR

我们已研究了如何使用 ATR 为智能系统生成入场和离场信号,即使这并不总是主要目的或用途。ATR 主要用于放置停止、或大多进行调仓;因此,我们在自定义类之内考察这些,即仍可由 MQL5 向导在智能系统中汇编。

我们在此保持实现简单,因此为了定义一个尾随停止,我们简单地按一个 ATR 倍数提升基准。出于我们的目的,我们的基准可以采用 3 种形式。原生价格、移动平均价格、和 SAR 指标价位。这些中的每一个,在它们自己的部分,都为我们提供了一个形态,我们将其索引为 0, 1 和 2,并按如下方式编码:

//+------------------------------------------------------------------+
//| Check for Pattern 0.                                             |
//+------------------------------------------------------------------+
void CTrailingATR::IsPattern_0(double &Price, ENUM_POSITION_TYPE T)
{  if(T == POSITION_TYPE_BUY)
   {  Price -= (m_stop_level * ATR(StartIndex()));
   }
   else if(T == POSITION_TYPE_SELL)
   {  Price += (m_stop_level * ATR(StartIndex()));
   }
}
//+------------------------------------------------------------------+
//| Check for Pattern 1.                                             |
//+------------------------------------------------------------------+
void CTrailingATR::IsPattern_1(double &Price, ENUM_POSITION_TYPE T)
{  if(T == POSITION_TYPE_BUY)
   {  Price = (MA(StartIndex()) - (m_stop_level * ATR(StartIndex())));
   }
   else if(T == POSITION_TYPE_SELL)
   {  Price = (MA(StartIndex()) + (m_stop_level * ATR(StartIndex())));
   }
}
//+------------------------------------------------------------------+
//| Check for Pattern 2.                                             |
//+------------------------------------------------------------------+
void CTrailingATR::IsPattern_2(double &Price, ENUM_POSITION_TYPE T)
{  if(T == POSITION_TYPE_BUY && SAR(StartIndex()) < Low(StartIndex()))
   {  Price = (SAR(StartIndex()) - (m_stop_level * ATR(StartIndex())));
   }
   else if(T == POSITION_TYPE_SELL && SAR(StartIndex()) > High(StartIndex()))
   {  Price = (SAR(StartIndex()) + (m_stop_level * ATR(StartIndex())));
   }
}

正如我们上面所做的那样,可以逐个形态执行优化和测试运行,不过为简洁起见,我们仅打算进行一次运行,来考察按不同权重优化所有形态的用法。这些结果如下所示:

atr_t_all

atr_c_t_all


资金管理中的 ATR

止损间隙在设置持仓规模时很实用。这是因为,论调是,若某人有一笔持仓,那么当交易对他们不利时,止损就是他们该笔持仓将遭受损失的最大上限。因此,通过衡量止损间隙的即刻数值,可以得出持仓规模的手数理论值,即触发止损不会超过当时可用保证金的设定百分比。

一旦有了止损价位和最大风险百分比,我们就能得到相应手数,即理论上我们能承受的亏损。这是理论上的,因为止损并不能保证实际价格。只有当该价格可用时,它们才会被触发,这就是为什么 2015 年 1 月对于瑞士法郎的交易员来说是毁灭性的。那么什么是最好的保险呢?最小且负责任地调仓。如果我们采用与上面尾随止损相同的 3 种不同的可能止损方法,这就是我们如何实现自定义资金管理类 3 种并列形态:

//+------------------------------------------------------------------+
//| Getting lot size for open long position.                         |
//+------------------------------------------------------------------+
double CMoneyATR::CheckOpenLong(double price, double sl)
{  if(m_symbol == NULL)
      return(0.0);
//--- select lot size
   double lot;
   if(price == 0.0)
      lot = m_account.MaxLotCheck(m_symbol.Name(), ORDER_TYPE_BUY, m_symbol.Ask(), m_percent);
   else
      lot = m_account.MaxLotCheck(m_symbol.Name(), ORDER_TYPE_BUY, price, m_percent);
//---
   double result  = 0.0, results = 0.0;
   price =m_symbol.Bid();
//--- if the model 0 is used and "ATR-Based Stop Loss"
   if(((m_patterns_usage & 0x01) != 0))
   {  IsPattern_0(price, POSITION_TYPE_BUY);
      result += m_pattern_0 * price;
      results += m_pattern_0;
   }
//--- if the model 1 is used and "ATR-MA-Channel Stop Loss"
   if(((m_patterns_usage & 0x02) != 0))
   {  IsPattern_1(price, POSITION_TYPE_BUY);
      result += m_pattern_1 * price;
      results += m_pattern_1;
   }
//--- if the model 2 is used and "ATR-SAR-Channel Stop Loss"
   if(((m_patterns_usage & 0x04) != 0))
   {  IsPattern_2(price, POSITION_TYPE_BUY);
      result += m_pattern_2 * price;
      results += m_pattern_2;
   }
//---
   if(results > 0)
   {  result /= results;
      double _risk = (fabs(m_symbol.Bid()-result)/m_symbol.Point())*(m_symbol.TickSize()/m_symbol.Point())*m_symbol.TickValue();
      _risk /= m_account.FreeMargin();
      _risk *= 100.0;
      double _risk_lots = m_percent/_risk;// where m_percent is also max risk
      lot = fmin(2.0*lot, fmax(_risk_lots, m_symbol.LotsMin()));
   }
//--- return trading volume
   return(Optimize(lot));
}
//+------------------------------------------------------------------+
//| Getting lot size for open short position.                        |
//+------------------------------------------------------------------+
double CMoneyATR::CheckOpenShort(double price, double sl)
{  if(m_symbol == NULL)
      return(0.0);
//--- select lot size
   double lot;
//---
   if(price == 0.0)
      lot = m_account.MaxLotCheck(m_symbol.Name(), ORDER_TYPE_SELL, m_symbol.Bid(), m_percent);
   else
      lot = m_account.MaxLotCheck(m_symbol.Name(), ORDER_TYPE_SELL, price, m_percent);
//---
   double result  = 0.0, results = 0.0;
   price =m_symbol.Ask();
//--- if the model 0 is used and "ATR-Based Stop Loss"
   if(((m_patterns_usage & 0x01) != 0))
   {  IsPattern_0(price, POSITION_TYPE_SELL);
      result += m_pattern_0 * price;
      results += m_pattern_0;
   }
//--- if the model 1 is used and "ATR-MA-Channel Stop Loss"
   if(((m_patterns_usage & 0x02) != 0))
   {  IsPattern_1(price, POSITION_TYPE_SELL);
      result += m_pattern_1 * price;
      results += m_pattern_1;
   }
//--- if the model 2 is used and "ATR-SAR-Channel Stop Loss"
   if(((m_patterns_usage & 0x04) != 0))
   {  IsPattern_2(price, POSITION_TYPE_SELL);
      result += m_pattern_2 * price;
      results += m_pattern_2;
   }
//---
   if(results > 0)
   {  result /= results;
      double _risk = (fabs(result-m_symbol.Ask())/m_symbol.Point())*(m_symbol.TickSize()/m_symbol.Point())*m_symbol.TickValue();
      _risk /= m_account.FreeMargin();
      _risk *= 100.0;
      double _risk_lots = m_percent/_risk;// where m_percent is also max risk
      lot = fmin(2.0*lot, fmax(_risk_lots, m_symbol.LotsMin()));
   }
//--- return trading volume
   return(Optimize(lot));
}

这种方式除了过度依赖可用止损价格的弱点外,在止损间隙非常小的情况下,时不时会存在分配过大手数的风险。这就是为什么我们要把手数标准化,且不超过可用保证金默认风险百分比的两倍。因此,该风险百分比(m_percent)有两个目的,一是它定义了我们交易手数的上限,它作为可用保证金的百分比,其二若我们在既定价位止损,它定义了理论上我们的亏损占最大可用保证金的百分比。

来自一些最优结果的测试运行,同样使用与上述类似的设置,为我们给出以下结果:

atr_m_r_all

atr_m_c_all

再一次,我们并未在每个形态的基础上运行测试,而只是优化了我们的智能系统,以便使用所有形态,尽管权重不同,就如上面的尾随止损一样。


结束语

我们已完结在上一篇文章中研究过的 ADX 指标,且从头至尾研究了 ATR 指标。本文提出了许多运用 ATR 的不同思路和实现;不过,为简洁起见,它们并未编码或测试。因此,欢迎读者自行实现和测试,最好能在更广泛的品种和更多历史数据上进一步发展,以便更好地掌握适合它们情况的境况。

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/16213

附加的文件 |
MoneyWZ_44.mqh (13.81 KB)
TrailingWZ_44.mqh (11.24 KB)
SignalWZ_44.mqh (15.63 KB)
wz_44_signal.mq5 (7.47 KB)
wz_44_trail.mq5 (8.35 KB)
wz_trail_mm_44.mq5 (9.07 KB)
使用 MetaTrader 5 的 Python 高频套利交易系统 使用 MetaTrader 5 的 Python 高频套利交易系统
在本文中,我们将创建一个在经纪商眼中仍然合法的套利系统,在外汇市场上创建数千个合成价格,对其进行分析,并成功交易以获取利润。
构建K线趋势约束模型(第九部分):多策略EA(2) 构建K线趋势约束模型(第九部分):多策略EA(2)
理论上,可以集成至EA中的策略数量没有上限。然而,每新增一种策略都会提升算法复杂度。通过融合多策略架构,EA能够更灵活地适应不同市场环境,从而可能提升整体盈利能力。今天,我们将探讨如何通过MQL5实现理查德·唐奇安(Richard Donchian)的经典通道突破策略,以此进一步拓展我们的趋势约束型EA功能体系。
MQL5 中的 SQLite 功能示例:按交易品种及 Magic 编码展示交易统计信息的仪表盘 MQL5 中的 SQLite 功能示例:按交易品种及 Magic 编码展示交易统计信息的仪表盘
本文将介绍如何创建一个指标型仪表盘,按账户、交易品种及交易策略展示交易统计信息。我们将以官方文档及数据库相关文章中的示例为基础,逐步实现完整程序。
如何使用 MetaTrader 和 Google Sheets 创建交易日志 如何使用 MetaTrader 和 Google Sheets 创建交易日志
使用 MetaTrader 和 Google Sheets 创建交易日志!您将学习如何通过 HTTP POST 同步您的交易数据,并使用 HTTP 请求来获取它。最后,您有一个交易日志,可以帮助您有效地跟踪您的交易。