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

量化交易吧 /  量化策略 帖子:3364712 新帖:33

交易货币篮子时可用的形态

我是游客发表于:4 月 17 日 17:29回复(1)

概论

我以前的 文章, 关于交易货币篮子的基本原则, 方法和术语。当然, 若想成功地遵循这种复杂的方法这些还不够。了解入场和离场条件, 以及信号, 仍然至关重要。换言之, 我们需要描述当前已知的, 可以显著提高盈利能力的形态。这是本文的目标 — 当处理货币篮子时, 为交易者提供已形成的形态详细描述。我们将使用的术语, 类似于之前文章中的篮子和技术工具的描述。我们还将应用威廉姆斯百分比范围 (WPR) 指标来分析货币篮子状态。

我们来简要描述这个指标。父辈的 WPR 数值范围从 0% 至 -100%。这个范围不适合我们, 原因如下所述。正确显示所有形态时, 需要转换的数值范围将超过零为 100% 到 -100%。这种变化可以很容易地在指标代码中完成。此外, 我们假设 父辈指标的现有超卖/超买级别仍然与合并后的级别相关, 因此我们将主动使用它们。


动态入场特征。形态 #1, 2

动态入场意味着当指标信号达到特定值时即入场, 而不必等待当前蜡烛收盘。首先, 我们来考虑一个货币篮子形态的直观强化/弱化。从市场的角度来看, 这意味着一个或多个事件的产生, 将令投资者买入或卖出某种货币, 并迫使它相对于其它货币升值或贬值。例如, 欧洲央行行长德拉吉的公开出面可能很容易令欧元相对于其它货币强势或弱势。在这种情况下, 组合的 WPR 接近该范围的上边界或下边界。交易者可在指标达到特定值之后入场, 而不必等待蜡烛收盘再执行动态入场。

  • 形态 #1

这种形态在众多标准技术指标的描述中经常可以找到。 

指标几乎触及边界, 然后反转并突破超买线向下或超卖线向上。这是篮子内所有货币的一个趋势跟随入场信号。

根据许多权威来源, 绝不应该动态地执行这样的入场。因此, 我强烈不推荐在交易中使用形态 #1。

  • 形态 #2

第二种形态是前一种形态的修改版本。

指标几乎触及范围边界, 并且将与当前趋势一起反转。这是篮子内所有货币的逆势入场信号。

根据单一指标读数预测即将发生的价格逆转是不正确的。但是, 请记住, 组合的 WPR 是一种不适合趋势交易的振荡器。在当前状况下, 指标可能在相当长的时间内徘徊于范围边界, 稍微偏离它们一点, 然后再次接近它们。与此同时, 当前的趋势持续令交易者的亏损扩大。当然, 终将会从边界回滚, 但它可能需要一段时间。没有人可以保证回撤能保持在可承受范围, 财会结果可能是毁灭性的。

不过, 有些交易者在指标显示的价值显著高于 90% 或低于 -90% 时使用此形态。原因是形态 #2 还具有显著的优点, 允许交易者在趋势开始时将其捕获。显然, 我们需要一些额外的入场信号。我们可以使用价格行为搜索它们。

此外, 如果它是由一条新传来的基本面消息而形成, 不建议交易这种形态。代之, 该形态在已形成的趋势中更可靠, 因为它也许暗示其接近末期。

例如, 我们可以在 2015 年 1 月中旬的黑天鹅事件期间使用 CHF 历史价格。历史监控记录附加在 CSV 文件 (MS Excel) 中。文件名对应于监控开始日期和时间。文件包含四个数据列:

监控时间 H1 指标读数 H4 指标读数 D1 指标读数
... ... ... ...
12:51:32 99.16 99.17 99.17
12:51:34 98.85 98.87 98.88
... ... ... ...

在此, 您可以看到较低时间帧相较于较高时间帧数据的变化, 以及指标读数是如何近乎抵达范围边界, 偏离并再次接近的。任何敢在这样的时刻入场的人, 肯定会迅速遭遇止损。

当然, 也可以在图表上找到对比例子, 当动态入场时带来的丰厚盈利。然而, 失败率奇高导致形态 #2 太冒险了。因此,我也不推荐它。


柱线收盘时入场。形态 #3

如果当前时间帧的蜡烛收盘之后, 组合 WPR 超买级别向下交叉, 或者超卖向上交叉, 则交易者收到篮子内所有货币对的入场信号

这种入场方法对于某些货币对是广为人知的。不过, 如果我们留意到, 组合指标继承了前一篇文章中指定的父辈属性, 那么在处理货币对篮子时, 超卖/超买级别突破的条目可以被认为是有效的。此外, 由于级别突破伴随着边界范围附近的指标反转 (这意味着存在一些, 尽管短暂的走势), 顺势入场。形态 #3 的主要条件是当前时间帧蜡烛收盘之后再识别趋势。

入场本身则以标准方式执行。交易者可以追随市价或使用限价订单。然而, 在第二种情况下, 入场可能不会体现在所有货币对上。这可能反过来导致整个篮子的买卖操作整体亏损。我们使用下面的例子来说明这一点。

一名交易者使用篮子内所有货币对入场, 记住, 并非所有的货币对最终都有利可图。一些货币对也许显示零结果, 而如果区域消息大多转为负面, 有一些也许会亏损。由于欧元区的问题和不良统计, 假定 EURJPY 图表以跌势为主已经持续一段时间。因此, EUR 篮子的组合 WPR 线向下并开始接近范围边界。此刻, 市场情绪变化, 统计变得更加利多, 投资者的信心恢复。EURJPY 走势变得平坦, 看涨走势似乎是不可避免的。组合的 WPR 线反转并穿越超卖线。交易者遵循信号入场买入 EUR 货币篮子。但出于某种原因, EURJPY 图表仍然保持平稳, 甚至倾向于看跌走势。

为什么?因为有关欧元的利多消息之后是日元的利多消息。因此, 投资者已经开始购买日元, 将它推动向上 (也许甚至比欧元更快), 因此导致平坦甚至看跌的走势。因此, 交易者对这对货币的期望被证明是错误的。但篮子里还有其它没有新统计数据的货币对。它们赚取了盈利。但如果交易者已经使用限价订单来买入欧元篮子, 情况也许已经变得更不利, 因为并非所有货币对都可能在入场窗口期间被触发。甚或, 只有一对 (EURJPY) 可能已触发, 整体造成亏损。

我们考虑一个来自实际的案例。我们使用同一对 EURJPY, 并在 H1 上启动 testWPR.mq5 测试指标:

//+------------------------------------------------------------------+
//|                                                      testWPR.mq5 |
//|                                        MetaQuotes 软件公司|
//|                                               http://fxstill.com |
//+------------------------------------------------------------------+
#property copyright "版权所有 2016, MetaQuotes 软件公司"
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum -100
#property indicator_maximum 100

#property indicator_buffers 1
#property indicator_plots   1

input int     WPR=14;                    // WRP 周期
input color   clr= clrBlue;

#define LG 7
string pair[]={"EURUSD","EURJPY","EURCHF","EURGBP","EURNZD","EURCAD","EURAUD"};
int h[LG];

double ind[];
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 指标缓存区映射
   for(int i=0; i<LG; i++)
     {
      h[i]=iWPR(pair[i],0,WPR);
     }
   ArraySetAsSeries(ind,true);
   SetIndexBuffer(0,ind);

   IndicatorSetString(INDICATOR_SHORTNAME,"testWPR");
   IndicatorSetInteger(INDICATOR_DIGITS,2);
   IndicatorSetInteger(INDICATOR_LEVELS,2);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,0,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,1,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,0,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,1,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,0,1);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,1,1);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,0,-60);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,1,60);

   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,clr);
   PlotIndexSetString(0,PLOT_LABEL,"_tstWPR_");

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetValue(int shift)
  {
   double dBuf[1];
   double res=0.0;
   for(int i=0; i<LG; i++)
     {
      CopyBuffer(h[i],0,shift,1,dBuf);
      res+=dBuf[0];
     }//结束 for (int i = 0; i < iCount; i++)      
   res=res/LG;
   return (NormalizeDouble((res + 50) * 2, _Digits) );
  }
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                                |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
      int rt=rates_total-WPR;
      for(int i=1; i<rt; i++)
        {
         ind[i]= GetValue(i);
        }
     }
   else
     {
     }
//--- 返回 prev_calculated 值用于下次调用
   return(rates_total);
  }
//+------------------------------------------------------------------+

void OnDeinit(const int reason)
  {
   for(int i=0; i<LG; i++)
     {
      if(h[i]!=INVALID_HANDLE) IndicatorRelease(h[i]);
     }
   string text;
   switch(reason)
     {
      case REASON_PROGRAM:
         text="指标通过调用 ExpertRemove() 函数终端其操作";break;
      case REASON_INITFAILED:
         text="此值意味着 OnInit() 处理器 "+__FILE__+" 已返回一个非零值";break;
      case REASON_CLOSE:
         text="终端已关闭"; break;
      case REASON_ACCOUNT:
         text="账户已改变";break;
      case REASON_CHARTCHANGE:
         text="品种或时间帧已改变";break;
      case REASON_CHARTCLOSE:
         text="图表已关闭";break;
      case REASON_PARAMETERS:
         text="输入参数已变更";break;
      case REASON_RECOMPILE:
         text="程序 "+__FILE__+" 已编译";break;
      case REASON_REMOVE:
         text="程序 "+__FILE__+" 已从图表上移除";break;
      case REASON_TEMPLATE:
         text="新模板已应用于图表";break;
      default:text="其它原因";
     }
   PrintFormat("%s",text);
  }
//+------------------------------------------------------------------+

由于组合 WPR 的范围是从 -100% 到 100%, 超买级别位于 60%, 而不是父辈 WPR 的 -20%。因此, 超卖级别在 -60%, 而非 -80%。牢记这一点, 我们在指标图表上标记这些级别。

我们应该分析超买/超卖级别交叉点。在写这篇文章的时候, 它在 H1 图表上位于一个三小时蜡烛的收盘 2016.10.17: 


我们假设我们已在那一刻入场。我们应事先定义离场点。当指标值即将离开或接近零轴时, 无论交易结果如何, 我们都将离场。这一刻将在同一天早上七点钟到来。我们用垂直线标记这两个点。EUR 篮子内其它货币对的截图可以在下面的归档中找到, 并且这些行已经被标记。注意 EURNZD 显示负结果, EURGBP 显示大约为零, 而剩余的五对则有盈利。

不过, 有个问题是超卖和超买级别是否正确。在比较前一篇文章中的标准和组合的随机振荡指标图表时, 很明显, 组合的指标更平滑。当比较标准和组合的 WPR 时, 可以看到同样的结果 (见下面的屏幕截图):

在此我们有组合的 (粗蓝线) 和标准 (浅蓝线) WPR 的图形。

组合指标的超买/超卖级别价值与父辈相比是否保持不变?为了回答这个问题, 我们需要进行广泛的研究, 以便找到一些确凿的证据。在本文的框架内, 我们只能进行非常粗糙 (主要是视觉上) 的评估。为了避免主观判断, 在这里提出个人观点似乎是不合适的。

还有一个关于这个形态 (和一些其它) 的问题。离场条件是什么?我们可以为这个问题提供两个答案:

  1. 根据价格行为规则, 不同货币对分别离场。这允许您使用已经熟悉的工具和尾随止损。但这是有风险的, 因为篮子也许不会完全关闭, 并且已开订单也许最终导致亏损超过获得的利润。当然, 交易者应负责防止这种情况。
  2. 根据指标读数, 立即从所有货币对中离场。例如, 交易者可以在超买级别 (-60%) 交叉之后买入篮子, 并且当指标达到零 (或 -10%) 时卖出。在这种情况下, 篮子完全关闭, 虽然并非所有的预期利润都能收到。

我们来汇总分析形态 #3 的结果:

  1. 该形态可以在交易中应用。它定义为蜡烛收盘之后, 并通过级别判断。穿越这些级别可作为可能的入场信号。
  2. 形态没有那些严格定义的入场和离场规则。然而, 确定入场信号的超卖和超买级别的存在是毋庸置疑的。
  3. 形态允许显著回撤。
  4. 形态不考虑每个货币对中存在的第二货币。这几乎是最显著的缺陷, 会导致 长期的 回撤, 以及亏损。
  5. 还有另一个缺点是隐含的, 但并不重要。正如我们前面提到的, 当处理货币对篮子时, 我们可能会得到负数、零和正数结果。交易者获取利润, 因为篮子内货币对的状态显示, 篮子内的大多数货币对在最有希望的方向上达到正面结果的概率增加。在此阶段, 交易结果也许会受到各种货币对的掉期、佣金和不同点价格的负面影响。

我们能否提高形态效率, 减少回撤并提高盈利能力呢?事实证明, 我们可以: 让我们转到下一个形态。

当一种货币正在走强, 而另一种货币正在疲软时入场。形态 #4

不像以前的形态, 这个考虑到了两种货币形成的价格。

例如, EURJPY 的价格向下移动可能有三种情况:

  • 第一货币变得更强 — EUR。这与已描述的形态 #3 及其所有的缺点和优点相关。
  • 第二货币变得疲软 — JPY。这也与形态 #3 相关。
  • 同一时刻 EUR 走强且 JPY 疲软。这一事件增加了逆转以及在利多方向上移动的概率。当货币走强和疲软时, 概率增加。

形态 #4 为第三点描述中定义的情形提供了一个入场信号。这会如下发生。

每个货币对由两种货币组成, 可能属于两个不同的篮子。例如, EURJPY 可以使用两个组合指标进行分析, 其中一个基于欧元, 另一个基于日元。因此, 两种货币中的每一种均可管理走强/疲软。更甚, 尽管 #4 是最重要的, 但是也可以识别形态 #3。

通过分析基准货币和报价货币的组合指标读数之间的图形差异来识别。虽然这个差额大约保持在 0%, 但行情是平坦的, 因为形成该货币对的两种货币具有近似相等的动力。投资者信任这两种货币, 消息大部分也是中性的, 所以没有剧烈的走势。因此, 组合指标为每种货币提供类似的价值, 它们之间的差别很小。看似此时不能入场是合理的。

但是状况开始改变。JPY 正在走强, 而 EUR 正在贬值。一段时间的持续, 意味着这是一种趋势, 而不是一次性的走势。交易者注意到组合指标的读数正在改变。欧元读数逐渐移向接近范围边界的负区域。日元正在显示相反的走势。EURJPY 图表倾向于做空。现在, 交易者要检查欧元和日元的综合指标图形之间的差异。它向下移动, 瞄准其最小值 -200%。

在相反走势的情况下, 最大值为 200%。我相信, 现在已很明显为什么我们需要改变组合 WPR 范围, 我已经在本文开头提到, 将其改为从 100% 到 -100%。这令我们可在单个窗口中放置组合指标图形并比较它们之间的差异。为了摆脱 200% 的 "不雅" 值, 两个组合指标之间的差值应该分成两半, 使其达到 100%。

因此, 当组合指标读数之间的差值达到某一值时, 交易者会收到入场信号。更具体地, 交易者等待, 直到差值图形接近范围边界之一, 反转并突破超卖线向下或超买线向上。突破应假定发生在蜡烛收盘时。换言之, 策略类似于形态 #3 中的策略, 虽然有一些区别:

  • 两个组合指标, 定义一个货币对中每种货币的状态, 以便做出交易决策, 增加潜在的盈利能力。
  • 入场是针对篮子内的一个货币对 (并非全部) 执行。因此, 我们设法减少亏损。

我们在实践中使用形态 #4。要达此目的, 我们应该为日元篮子创造另一个指标。我们将采用与 testWPR 相同的方式开发它。日元篮子货币对的列表取自上一篇文章。由于指标代码与 testWPR 类似, 因此在此不显示。编译的指标代码附于文章之后。我们只需要将指标颜色更改为红色, 并将其放在 EURJPY 同一个窗口内, 其中 testWPR 已经存在。结果显示如下: 

感兴趣的重点是垂直线标注。即使这样的一个小片段, 令我们可以看到价格图表和指标之间的差值 (最弱和最强货币之间的距离)。

不过, 难以在这样的图表上跟踪期望的差值。我们来编写另一个测试指标 testDistance.mq5:

//+------------------------------------------------------------------+
//|                                                 testDistance.mq5 |
//|                                   2016 MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "版权所有 2016, MetaQuotes 软件公司"
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum -100
#property indicator_maximum 100

#property indicator_buffers 1
#property indicator_plots   1

input int WPR = 14;//Period WPR
input color   clr= clrGreen;

double ind[];
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                            |
//+------------------------------------------------------------------+
int h,h1;
int OnInit()
  {
//--- 指标缓存区映射
      h = iCustom(NULL,0,"testWPR",WPR);
      if (h == INVALID_HANDLE) {
         Print("创建 testWPR 出错");
         return (INIT_FAILED);
      }
      h1 = iCustom(NULL,0,"testWPRjpy",WPR);
      if (h1 == INVALID_HANDLE) {
         Print("创建 testWPRjpy 出错");
         return (INIT_FAILED);
      }  
   ArraySetAsSeries(ind,true);
   SetIndexBuffer(0,ind);        
  
   IndicatorSetString(INDICATOR_SHORTNAME,"testWPRdistance");
   IndicatorSetInteger(INDICATOR_DIGITS,2);
   IndicatorSetInteger(INDICATOR_LEVELS,2);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,0,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,1,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,0,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,1,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,0,1);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,1,1);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,0,-60);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,1,60);

   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,clr);
   PlotIndexSetString(0,PLOT_LABEL,"_tstWPRdistance_");    
//---
   return(INIT_SUCCEEDED);
  }
  
double GetValue(int shift)
  {
   double dBuf[1], dBuf1[1];
   double res=0.0;
   CopyBuffer(h,0,shift,1,dBuf);
   CopyBuffer(h1,0,shift,1,dBuf1);
   return (NormalizeDouble((dBuf[0] - dBuf1[0])/2, _Digits) );
  }  
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                                |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
      int rt=rates_total-WPR;
      for(int i=1; i<rt; i++)
        {
         ind[i]= GetValue(i);
        }
     }
   else
     {
     }
//--- 返回 prev_calculated 值用于下次调用
   return(rates_total);
  }
void OnDeinit(const int reason)
  {
   IndicatorRelease(h);
   IndicatorRelease(h1);

  }
//+------------------------------------------------------------------+

将它放在 EURJPY 的单独窗口, 并检查以前标记的区域:


欧元和日元的两个组合 WPR 之间的差值显示为绿线。有趣的是, 考察强势货币和弱势货币之间的差值, 如何与当前趋势及其逆转相关。在此, 我们还可以谈论超买/超卖区域, 以及有关区域交叉之后如何在蜡烛收盘时识别形态 #4 (参见最后的屏幕截图)。在此情况下, 如果一名交易者在 10 月 21 日 (11:00) 入场, 他们将能够捕捉到从头迄今 (11 月 1 日) 尚未结束的趋势。 

因此, 在实现阶段使用形态 #4 类似于使用一般订单, 而非类似于形态 #3 情况下的一揽子订单。因此, 我们的预期回撤可以大幅下降。我们也可以预期盈利交易数量增加 (但并非它们的总数), 因为形态 #4 增加了盈利的概率。请记住, 我们可以应用尾随止损并使用我们可用的其它工具, 因为只有一笔订单, 它可以沿用通常的方式。

形态 #4 还可作为滤波器与形态 #3 一起使用。可以根据形态 #3 针对篮子内所有货币对执行入场, 而基于形态 #4 的过滤器能够分离出其中的一些。所以, 在几个货币对上可能会接近第三种形态的总收益率, 同时保持第四种形态的优点。当然, 这只是我的理论。我并未在真实交易中测试形态的组合。

现在, 我们来描述当形态 #4 给出错误信号时的情况。有几种状况十分明显, 当组合指标朝向范围边界移动, 且随后以其它货币对为代价发生逆转, 而此刻交易者即将交易此货币对, 但尚未出手。我们应该理解, 一个篮子包含多个货币对时, 组合指标显示一个平均值。局部事件可能对交易者入场的货币对造成负面影响。我在描述形态 #3 时已经提及。对于形态 #4 也是如此, 尽管概率低得多。

我们来总结一下形态 #4 的数据。

优点:

  1. 增加盈利的概率。
  2. 减低回撤。
  3. 很希望计划内利润能在更短的时间内实现。也许, 这并非单独入场的优势, 而是对第一个优势的补充。 
  4. 交易者不必处理一篮子订单, 而是交易单一订单。因此, 跟踪交易很简单。 

缺点:

  1. 适于识别形态 #4 的条件不是很常见。
  2. 总利润较低, 因为只有一笔订单是有利可图的。 

我们来尝试减少第四种形态缺点的负面影响。为做到这一点, 当一种货币严重贬值, 而另一种太强势时, 我们应该定义是否有办法增加交易数量, 而不是使用形态 #4。也许, 除了超买/超卖级别的突破之外, 还有另一种入场的方式:

参考移动平均值入场。形态 #5

移动平均是一种公认并受到敬仰的行情分析方法。许多指标和 EA 在其计算中用到它。我们假设超买/超卖级别在 WPR 组合中工作。对于两个组合 WPR 之间的差值也是如此。因此, 没有什么能阻止我们向指标图形里添加移动平均值。

显然, 我们可以将其添加到第三种和第四种形态检测图形中。我相信, 描述移动平均线背后的思路没有意义。其优点和缺点 (包括其滞后特性) 也是众所周知的。考虑所有这些, 我们能够分析在图形上放置移动平均值的结果, 以便找到形态 #5:

当指标图形穿越移动平均值时, 交易者收到入场信号。假设当前时间帧的蜡烛收盘时发生此事件。

这种交叉十分频繁, 尤其是如果我们使用快速 MA, 因而交易数量增加。从现在开始, 我们将分析位于第四种形态检测图形上的 MA。读者可以在第三种形态检测中分析 MA 的应用。

您也许会问: 单独形态调用 MA 应用程序是否正确?是否它只是形态 #4 的附加过滤器?不, 它是一个单独形态。有时, 超买/超卖级别的突破几乎同时伴随指标图形穿越 MA。在此情况下, 形态 #4 和形态 #5 彼此强化, 使得定义它们当中谁 "最重要" 变得不可能。在其它情况下, 形态 #4 是独立形态, 与穿越 MA 的图形无关 (形态 #5)。

无论如何, 我们来引入一些规则:

  • 如果形态 #5 "先于" 形态 #4 (即, 在范围边界和超卖/超买级别之间被识别), 则不要交易。
  • 在其它情况下, 决定入场, 而不管形态 #4 是否先于形态 #5。

第二条规则应该更彻底地落实。为了利用形态 #5 分析可能的状况, 我们应该创建一个新的指标 (本文中的最后一个指标):

//+------------------------------------------------------------------+
//|                                                 testDistance.mq5 |
//|                                   2016 MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "版权所有 2016, MetaQuotes 软件公司"
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum -100
#property indicator_maximum 100

#property indicator_buffers 2
#property indicator_plots   2

input int WPR       = 14; // WPR 周期
input int maperiod  = 10; // MA 周期
input color   clr   = clrGreen;
input color   clrMA = clrMagenta;


double ind[],ma[];
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                            |
//+------------------------------------------------------------------+
int h,h1;
int OnInit()
  {
//--- 指标缓存区映射
      h = iCustom(NULL,0,"testWPR",WPR);
      if (h == INVALID_HANDLE) {
         Print("创建 testWPR 出错");
         return (INIT_FAILED);
      }
      h1 = iCustom(NULL,0,"testWPRjpy",WPR);
      if (h1 == INVALID_HANDLE) {
         Print("创建 testWPRjpy 出错");
         return (INIT_FAILED);
      }  
   ArraySetAsSeries(ind,true);
   SetIndexBuffer(0,ind);        
  
   IndicatorSetString(INDICATOR_SHORTNAME,"testWPRdistance");
   IndicatorSetInteger(INDICATOR_DIGITS,2);
   IndicatorSetInteger(INDICATOR_LEVELS,2);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,0,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,1,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,0,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,1,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,0,1);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,1,1);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,0,-60);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,1,60);

   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,clr);
   PlotIndexSetString(0,PLOT_LABEL,"_tstWPRdistance_");    
  
   ArraySetAsSeries(ma,true);  
   SetIndexBuffer(1,ma);
   PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE           );
   PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID            );
   PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 1            );
   PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrMA            );
   PlotIndexSetString (1, PLOT_LABEL, "Middle_Basket_line_MA" );    
//---
   return(INIT_SUCCEEDED);
  }
  
double GetValue(int shift)
  {
   double dBuf[1], dBuf1[1];
   double res=0.0;
   CopyBuffer(h,0,shift,1,dBuf);
   CopyBuffer(h1,0,shift,1,dBuf1);
   return (NormalizeDouble((dBuf[0] - dBuf1[0])/2, _Digits) );
  }  
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                                |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
      int rt=rates_total-WPR;//-maperiod;
  
      for(int i=1; i<rt; i++)
        {
         ind[i]= GetValue(i);
        }
      rt -= maperiod;  
      for (int i = 1; i< rt; i++)
        {
         ma[i] = GetMA(ind, i, maperiod, _Digits);
        }
     }
   else
     {
     }
//--- 返回 prev_calculated 值用于下次调用
   return(rates_total);
  }
void OnDeinit(const int reason)
  {
   IndicatorRelease(h);
   IndicatorRelease(h1);
   string text;
   switch(reason)
     {
      case REASON_PROGRAM:
         text="指标通过调用 ExpertRemove() 函数终端其操作";break;
      case REASON_INITFAILED:
         text="此值意味着 OnInit() 处理器 "+__FILE__+" 已返回一个非零值";break;
      case REASON_CLOSE:
         text="终端已关闭"; break;
      case REASON_ACCOUNT:
         text="账户已改变";break;
      case REASON_CHARTCHANGE:
         text="品种或时间帧已改变";break;
      case REASON_CHARTCLOSE:
         text="图表已关闭";break;
      case REASON_PARAMETERS:
         text="输入参数已变更";break;
      case REASON_RECOMPILE:
         text="程序 "+__FILE__+" 已编译";break;
      case REASON_REMOVE:
         text="程序 "+__FILE__+" 已从图表上移除";break;
      case REASON_TEMPLATE:
         text="新模板已应用于图表";break;
      default:text="其它原因";
     }
   PrintFormat("%s",text);
  }
//+------------------------------------------------------------------+

double GetMA(const double& arr[], int index , int period, int digit) {
   double m = 0;
   for (int j = 0; j < period; j++)  m += arr[index + j];
   m /= period;
   return (NormalizeDouble(m,digit));
}

我们将指标放在相同的品种上。结果提供如下:


此处, 移动平均值显示为深红细线。包含形态 #5 的一些片段可以被识别并由垂直线标记。蓝线代表买入信号, 而红线代表卖出信号。我们可以很容易地看到差值图形与 MA 交叉的一些点未被标记。我们来解释这条在脑海里保留的先前引入的规则。

我们应将整个指标范围划分为几个区域, 并为形态 #5 设置最终规则:

  • 如果 MA/指标图形交叉出现在指标边界和超卖/超买区域之间的某个点, 则忽略信号。这些点是区域 #0 (零区域)。有两个这样的区域 (见截图)。
  • 正如我已经提到的, 形态 #4 和 #5 可以同时发生并彼此增强。如果交易者识别出形态 #4 (或 #4 和 #5) 并入场, 则他们应该考虑忽略所有后续形态 #5, 直到使用形态 #4 离场。
  • 随着时间的推移, 强势货币可能会减弱, 而弱势货币可能增长更强, 或者弱势货币可能会继续走弱, 而强势货币也可能开始向下移动, 或者两种货币都可能开始走强。在任何情况下, 指标图形将开始离开范围边界和超买/超卖级别。图形将移动到指标的零值, 意味着每种货币的强度大致相等。因此, 当前趋势逐渐结束变得平坦, 而这可能转变为反转, 且重复轮回。这是离场信号。当两种货币的动力大致相等时, 滞留在场内是危险的, 因为逆转的可能性很高。我们将零区域称为区域 #3。您可以自己定义它的边界, 虽然我喜欢 10% 和 -10% 之间的间隔。在此, 所有的形态 #5 被忽略, 而先前已开交易要考虑平仓 (至少部分) 或移动到盈亏平衡。
  • 当使用形态 #5 时, 仅有两个区域 适合交易:
    • 区域 #1 用于买入。相应的交易在最后一个屏幕截图上显示为蓝色垂直线。形态 #5 越接近区域 #1 和 #0之间的边界, 交易形态带来盈利的概率越大。
    • 区域 #2 用于卖出。相应的交易在最后一个屏幕截图上显示为红色垂直线。形态越接近区域 #2 的上边界, 盈利的概率越高。

    重要的一般规则: 在区域 #2 内形成的买入形态 #5 被忽略。在区域 #1 内形成的卖出形态 #5 也被忽略。

形态 #5 与形态 #4 具有相同的问题:

  • 也许它会发生在交易者即将入场交易之外的货币对。换句话说, 负面结果的风险仍然存在, 但我们考虑了所有可能的方法来减少它。

一些通盘考虑

所有已描述的形态有一个共同点: 超买/超卖级别的突破被认为是在当前时间帧蜡烛收盘之后发生的。假设我们要修复超买级别的突破。在组合 WPR 窗口中, 级别位于 60%。图表上升到 61.5%, 但在蜡烛收盘时跌回到 59%。我们应认定这是一个突破亦或不是?技术上, 条件已满足。但是这种微观形态值得交易吗?

另一种状况发生的频率比您想象的要多: 一根大实体蜡烛形成, 蜡烛收盘时的指标值为零, 甚至接近该范围的相对边界。再次, 突破在技术上是存在的, 但是形态值得交易吗?

我相信, 我们应该只交易清晰可见的形态, 这样不会造成任何疑虑。这类似于在绘制支撑/阻力线时应用的规则: 线应该是清晰和无可争议的。说到前一种情况, 如果指标值从 70% 左右下降到 45-55% 的级别, 超买级别的突破将被认定发生。此外, 有可能向零区移动, 您可以平仓或制定一些其它交易决定。

MA 穿越指标图性时也是如此。这种交叉应该发生在必要的区域, 并且清楚和明显, 甚至可以说 "优美"。如果指标图形在 MA 附近开始移动, 在一个方向上稍微交叉, 然后向另一个方向移动, 则考虑忽略此形态。

换句话说, 不确定、有争议的形态应被视为高风险形态, 并跳过。无论如何, 这是作者的个人观点, 反映了他在市场上的观点。因此, 不能将其认定为公理。


结论

使用组合 WPR 指标的示例在此已全部编写完毕, 所有内容也适用于基于振荡器的其它组合指标。这为我们提供了明确的超买/超卖级别, 保持振荡器的限制, 意味着可能有其它有趣的工具可以应用于交易货币对篮子。

全部回复

0/140

量化课程

    移动端课程