交易货币篮子时可用的形态·进阶篇
📊

交易货币篮子时可用的形态·进阶篇

(2/3)·从动态入场到均线参考,4类形态拆解篮子内货币的强弱转换逻辑

进阶 第 2/3 篇
很多交易者把标准WPR直接套到货币篮子上,却发现超买超卖信号频繁失灵。篮子组合的指标范围需要重标定到100%至-100%,否则边界形态根本看不清。先改好指标再谈形态,能少交不少学费。

◍ 篮子离场点与组合WPR的视觉校验

假设已在信号触发那一刻入场,离场点必须事先定义:当指标值逼近或即将下穿零轴时,不论盈亏都退出,这个时刻通常落在当天早七点。用垂直标线把入场与离场两个节点画出来,EUR篮子内其余货币对也照此处理。实际截图中EURNZD为负收益,EURGBP近似为零,另外五对均为盈利,说明篮子内部结果分化是常态。 组合WPR(粗蓝线)与标准WPR(浅蓝线)叠图对比,能直接看出组合版本更平滑,和标准随机振荡指标的结论一致。但父级与组合的超买/超卖阈值是否该保持一致,原文只做了粗略的视觉评估,没给统计证据,不宜主观下定论。 离场有两种思路:按价格行为规则逐对退出,可用熟悉工具和尾随止损,但篮子可能关不全,亏损超过利润的概率存在,需交易者主动防失控;按指标读数统一退,例如-60%交叉后买篮子,-10%或零轴卖出,篮子能全平,但会牺牲部分预期利润。 形态3可落地:蜡烛收盘后穿阈值作为可能的入场信号,超买超卖级别明确,但入场离场规则不严。显著缺陷是不看每个货币对的第二货币,容易带来长期回撤和亏损;掉期、佣金、点值差异也会侵蚀篮子利润。想压回撤提效率,得看下一个形态。

双币强弱差触发单一货币对入场

形态 #4 的核心不在单币种动能,而在货币对两端各自的强弱分化。以 EURJPY 为例,欧元走强、日元疲软同时发生,比仅一端变化更能抬升逆转与顺势移动的概率,这种双向背离才是入场依据。 具体识别靠两个组合 WPR 指标:一个跟踪基准币(如 EUR),一个跟踪报价币(如 JPY),同窗叠放。两者读数差约在 0% 附近时行情平坦;差值向 -200% 或 +200% 极端走,意味着两币动力拉开。为去掉不雅的 200% 边界,实盘把差值除以 2,压缩到 ±100% 区间,超买/超卖线设在 ±60%。 策略上等待差值线逼近年边界后反转,并突破超卖线向下或超买线向上,且突破以蜡烛收盘确认——类似形态 #3,但只做篮子内某一个货币对,而非整篮下单,回撤倾向更低。 下面这段 testDistance.mq5 就是算 EUR 与 JPY 组合 WPR 半差值的独立窗口指标: //+------------------------------------------------------------------+

//testDistance.mq5
//2016 MetaQuotes Software Corp.
//[MQL5官方文档]

//+------------------------------------------------------------------+ #property copyright "版权所有 2016, MetaQuotes 软件公司" #property link "[MQL5官方文档] #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==0rates_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); } //+------------------------------------------------------------------+ 逐行拆解要点:iCustom 分别加载 testWPR 与 testWPRjpy 两个句柄,失败即终止初始化;IndicatorSetDouble 把 ±60 写成红实线水平位,对应前面说的压缩后超买超卖边界;GetValue 里 CopyBuffer 取两指标当前值,相减除以 2 即得半差值并归一化;OnCalculate 仅在首次或跳变时回填 ind 数组,避免每 tick 重算。 把该指标挂到 EURJPY 副窗,能直接看强弱差绿线。实例中 10 月 21 日 11:00 差值下破 -60 且收线确认,至 11 月 1 日那段下行趋势仍延续,单一订单即可吃到这段。外汇与贵金属杠杆高,这类信号失效时局部reverse可能以其它币对为代价发生,实盘务必自验。 形态 #4 还能当形态 #3 的过滤器:篮内全开按 #3,用 #4 差值剔掉弱势组合,理论上网总收益接近 #3 且保留低回撤优点,不过作者未在真实账户验证过组合。缺点也直白——合适条件不常出现,且总利润因仅单笔下注而偏低。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+ //|                                                 testDistance.mq5 | //|                                   class="num">2016 MetaQuotes Software Corp. | //|                                              [MQL5官方文档] | //+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "版权所有 class="num">2016, MetaQuotes 软件公司" class="macro">#class="kw">property link      "[MQL5官方文档] class="macro">#class="kw">property version   "class="num">1.00" class="macro">#class="kw">property indicator_separate_window class="macro">#class="kw">property indicator_minimum -class="num">100 class="macro">#class="kw">property indicator_maximum class="num">100 class="macro">#class="kw">property indicator_buffers class="num">1 class="macro">#class="kw">property indicator_plots   class="num">1 input class="type">int WPR = class="num">14; //Period WPR input class="type">color clr= clrGreen; class="type">class="kw">double ind[]; //+------------------------------------------------------------------+ //| 自定义指标初始化函数                                           | //+------------------------------------------------------------------+ class="type">int h,h1; class="type">int OnInit()   { //--- 指标缓存区映射       h = iCustom(NULL,class="num">0,"testWPR",WPR);       if(h == INVALID_HANDLE) { Print("创建 testWPR 出错"); class="kw">return(INIT_FAILED); }       h1 = iCustom(NULL,class="num">0,"testWPRjpy",WPR);       if(h1 == INVALID_HANDLE) { Print("创建 testWPRjpy 出错"); class="kw">return(INIT_FAILED); }    ArraySetAsSeries(ind, true);    SetIndexBuffer(class="num">0,ind);            IndicatorSetString(INDICATOR_SHORTNAME,"testWPRdistance");    IndicatorSetInteger(INDICATOR_DIGITS,class="num">2);    IndicatorSetInteger(INDICATOR_LEVELS,class="num">2);    IndicatorSetInteger(INDICATOR_LEVELSTYLE,class="num">0,STYLE_SOLID);    IndicatorSetInteger(INDICATOR_LEVELSTYLE,class="num">1,STYLE_SOLID);    IndicatorSetInteger(INDICATOR_LEVELCOLOR,class="num">0,clrRed);    IndicatorSetInteger(INDICATOR_LEVELCOLOR,class="num">1,clrRed);    IndicatorSetInteger(INDICATOR_LEVELWIDTH,class="num">0,class="num">1);    IndicatorSetInteger(INDICATOR_LEVELWIDTH,class="num">1,class="num">1);    IndicatorSetDouble(INDICATOR_LEVELVALUE,class="num">0,-class="num">60);    IndicatorSetDouble(INDICATOR_LEVELVALUE,class="num">1,class="num">60);    PlotIndexSetInteger(class="num">0,PLOT_DRAW_TYPE,DRAW_LINE);    PlotIndexSetInteger(class="num">0,PLOT_LINE_STYLE,STYLE_SOLID);    PlotIndexSetInteger(class="num">0,PLOT_LINE_WIDTH,class="num">2);    PlotIndexSetInteger(class="num">0,PLOT_LINE_COLOR,clr);    PlotIndexSetString(class="num">0,PLOT_LABEL,"_tstWPRdistance_");     //---    class="kw">return(INIT_SUCCEEDED);   }  class="type">class="kw">double GetValue(class="type">int shift)   {    class="type">class="kw">double dBuf[class="num">1],dBuf1[class="num">1];    class="type">class="kw">double res=class="num">0.0;    CopyBuffer(h,class="num">0,shift,class="num">1,dBuf);    CopyBuffer(h1,class="num">0,shift,class="num">1,dBuf1);    class="kw">return(NormalizeDouble((dBuf[class="num">0]-dBuf1[class="num">0])/class="num">2,_Digits));   } //+------------------------------------------------------------------+ //| 自定义指标迭代函数                                             | //+------------------------------------------------------------------+ class="type">int OnCalculate(class="kw">const class="type">int rates_total,                  class="kw">const class="type">int prev_calculated,                  class="kw">const class="type">class="kw">datetime &time[],                  class="kw">const class="type">class="kw">double &open[],                  class="kw">const class="type">class="kw">double &high[],                  class="kw">const class="type">class="kw">double &low[],                  class="kw">const class="type">class="kw">double &close[],                  class="kw">const class="type">long &tick_volume[],                  class="kw">const class="type">long &volume[],                  class="kw">const class="type">int &spread[])   {    if(prev_calculated==class="num">0 || rates_total>prev_calculated+class="num">1)      {       class="type">int rt=rates_total-WPR;       for(class="type">int i=class="num">1;i<rt;i++)        {         ind[i]=GetValue(i);        }      }    else      {      } //--- 返回 prev_calculated 值用于下次调用    class="kw">return(rates_total);   } class="type">void OnDeinit(class="kw">const class="type">int reason)   {    IndicatorRelease(h);    IndicatorRelease(h1);   } //+------------------------------------------------------------------+

「把均线搬进 WPR 组合找穿越信号」

移动平均线的滞后性是老生常谈,但在 WPR 组合图形里加一条 MA,能直接把“指标线穿越均线”变成可执行的形态 #5 入场逻辑。假设穿越发生在当前周期蜡烛收盘时,信号才算数,这样能过滤掉盘中毛刺。 用快速 MA 时穿越非常频繁, fourth 形态检测图上的交易次数会明显变多;原文建议重点看第四种形态检测图,第三种图留给你自己验证。形态 #4(边界突破)和形态 #5(穿越 MA)有时会几乎同时发生,两者相互强化,硬分主次没意义,但形态 #4 也可能独立出现,与 MA 无关。 规则要钉死:如果形态 #5 先于形态 #4 出现在“范围边界和超卖/超买级别之间”,直接放弃交易;其他情况无论谁先谁后都允许入场。外汇与贵金属杠杆高,穿越信号假突破概率不低,实盘前先在 MT5 用历史数据数一下穿越次数再决定周期。 为落地形态 #5 的分析,需要新建一个指标(也是本系列最后一个),把 MA 画进第四种形态检测图即可手动回看信号分布。

◍ 用双品种 WPR 差值过滤假交叉

把两个不同报价来源的 WPR 指标(例如主品种与交叉盘变体)同时加载,用 iCustom 取各自缓冲,再算 (Buf0 - Buf1)/2 作为差值序列,就能得到一条独立于绝对超买超卖的「背离距离」线。下面这段代码在副图窗口跑,上下界设 ±100,并画了 ±60 两条红色参考线。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                 testDistance.mq5 |
class=class="str">"cmt">//|                                   class="num">2016 MetaQuotes Software Corp. |
class=class="str">"cmt">//|                                              [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "版权所有 class="num">2016, MetaQuotes 软件公司"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_minimum -class="num">100
class="macro">#class="kw">property indicator_maximum class="num">100
class="macro">#class="kw">property indicator_buffers class="num">2
class="macro">#class="kw">property indicator_plots   class="num">2
input class="type">int WPR       = class="num">14;    class=class="str">"cmt">// WPR 周期
input class="type">int maperiod  = class="num">10;    class=class="str">"cmt">// MA 周期
input class="type">color clr     = clrGreen;
input class="type">color clrMA   = clrMagenta;
class="type">class="kw">double ind[],ma[];
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自定义指标初始化函数                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int h,h1;
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 指标缓存区映射
   h = iCustom(NULL,class="num">0,"testWPR",WPR);
   if(h==INVALID_HANDLE){ Print("创建 testWPR 出错"); class="kw">return(INIT_FAILED);}
   h1 = iCustom(NULL,class="num">0,"testWPRjpy",WPR);
   if(h1==INVALID_HANDLE){ Print("创建 testWPRjpy 出错"); class="kw">return(INIT_FAILED);}
   ArraySetAsSeries(ind,true);
   SetIndexBuffer(class="num">0,ind);
   IndicatorSetString(INDICATOR_SHORTNAME,"testWPRdistance");
   IndicatorSetInteger(INDICATOR_DIGITS,class="num">2);
   IndicatorSetInteger(INDICATOR_LEVELS,class="num">2);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,class="num">0,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,class="num">1,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,class="num">0,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,class="num">1,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,class="num">0,class="num">1);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,class="num">1,class="num">1);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,class="num">0,-class="num">60);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,class="num">1,class="num">60);
   PlotIndexSetInteger(class="num">0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(class="num">0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(class="num">0,PLOT_LINE_WIDTH,class="num">2);
   PlotIndexSetInteger(class="num">0,PLOT_LINE_COLOR,clr);
   PlotIndexSetString(class="num">0,PLOT_LABEL,"_tstWPRdistance_");
   ArraySetAsSeries(ma,true);
   SetIndexBuffer(class="num">1,ma);
   PlotIndexSetInteger(class="num">1,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(class="num">1,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(class="num">1,PLOT_LINE_WIDTH,class="num">1);
   PlotIndexSetInteger(class="num">1,PLOT_LINE_COLOR,clrMA);
   PlotIndexSetString(class="num">1,PLOT_LABEL,"Middle_Basket_line_MA");
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class="type">class="kw">double GetValue(class="type">int shift)
  {
   class="type">class="kw">double dBuf[class="num">1],dBuf1[class="num">1];
   class="type">class="kw">double res=class="num">0.0;
   CopyBuffer(h,class="num">0,shift,class="num">1,dBuf);
   CopyBuffer(h1,class="num">0,shift,class="num">1,dBuf1);
   class="kw">return(NormalizeDouble((dBuf[class="num">0]-dBuf1[class="num">0])/class="num">2,_Digits));
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自定义指标迭代函数                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(class="kw">const class="type">int rates_total,
                class="kw">const class="type">int prev_calculated,
                class="kw">const class="type">class="kw">datetime &time[],
                class="kw">const class="type">class="kw">double &open[],
                class="kw">const class="type">class="kw">double &high[],
                class="kw">const class="type">class="kw">double &low[],
                class="kw">const class="type">class="kw">double &close[],
                class="kw">const class="type">long &tick_volume[],
                class="kw">const class="type">long &volume[],
                class="kw">const class="type">int &spread[])
  {
   if(prev_calculated==class="num">0 || rates_total>prev_calculated+class="num">1)
     {
      class="type">int rt=rates_total-WPR;
      for(class="type">int i=class="num">1;i<rt;i++)
        {
         ind[i]=GetValue(i);
        }
      rt -= maperiod;
      for(class="type">int i=class="num">1;i<rt;i++)
        {
         ma[i]=GetMA(ind,i,maperiod,_Digits);
        }
     }
   else
     {
     }
class=class="str">"cmt">//--- 返回 prev_calculated 值用于下次调用
   class="kw">return(rates_total);
  }
class="type">void OnDeinit(class="kw">const class="type">int reason)
  {
   IndicatorRelease(h);
   IndicatorRelease(h1);
   class="type">class="kw">string text;
   class="kw">switch(reason)
     {
      case REASON_PROGRAM: text="指标通过调用 ExpertRemove() 函数终端其操作"; class="kw">break;
      case REASON_INITFAILED: text="此值意味着 OnInit() 处理器 "+__FILE__+" 已返回一个非零值"; class="kw">break;
      case REASON_CLOSE: text="终端已关闭"; class="kw">break;
      case REASON_ACCOUNT: text="账户已改变"; class="kw">break;
      case REASON_CHARTCHANGE: text="品种或时间帧已改变"; class="kw">break;
      case REASON_CHARTCLOSE: text="图表已关闭"; class="kw">break;
      case REASON_PARAMETERS: text="输入参数已变更"; class="kw">break;
      case REASON_RECOMPILE: text="程序 "+__FILE__+" 已编译"; class="kw">break;
      case REASON_REMOVE: text="程序 "+__FILE__+" 已从图表上移除"; class="kw">break;
      case REASON_TEMPLATE: text="新模板已应用于图表"; class="kw">break;
      class="kw">default:text="其它原因";
     }
   PrintFormat("%s",text);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double GetMA(class="kw">const class="type">class="kw">double &arr[],class="type">int index,class="type">int period,class="type">int digit)
{
   class="type">class="kw">double m=class="num">0;
   for(class="type">int j=class="num">0;j<period;j++) m+=arr[index+j];
   m/=period;
   class="kw">return(NormalizeDouble(m,digit));
}
逐行看关键处:iCustom 两次分别抓 testWPR 与 testWPRjpy 的句柄,失败就 INIT_FAILED 退出;GetValue 里 CopyBuffer 取各自身 0 号缓冲,相减除以 2 归一化,这就是差值线 ind[]。OnCalculate 中先填 ind,再对 ind 跑一遍周期为 10 的简单移动平均得到 ma[],MA 用深红细线绘制。 回测观察显示,当 MA 与差值线交叉发生在 ±60 参考线和 ±100 边界之间的「零区域」时,信号可靠性明显偏弱,这类交叉点截图里能看到未被垂直线标记。把副图划成零区域与超买/超卖区后,形态 #5 的最终规则倾向为:交叉落在区间中部就忽略。 别把交叉当万能 若已识别形态 #4 或其与 #5 共振入场,后续出现的 #5 交叉在平仓前大概率该直接跳过。外汇与贵金属杠杆高,忽略这条过滤可能放大回撤。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                 testDistance.mq5 |
class=class="str">"cmt">//|                                   class="num">2016 MetaQuotes Software Corp. |
class=class="str">"cmt">//|                                              [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "版权所有 class="num">2016, MetaQuotes 软件公司"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_minimum -class="num">100
class="macro">#class="kw">property indicator_maximum class="num">100
class="macro">#class="kw">property indicator_buffers class="num">2
class="macro">#class="kw">property indicator_plots   class="num">2
input class="type">int WPR       = class="num">14;    class=class="str">"cmt">// WPR 周期
input class="type">int maperiod  = class="num">10;    class=class="str">"cmt">// MA 周期
input class="type">color clr     = clrGreen;
input class="type">color clrMA   = clrMagenta;
class="type">class="kw">double ind[],ma[];
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自定义指标初始化函数                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int h,h1;
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 指标缓存区映射
   h = iCustom(NULL,class="num">0,"testWPR",WPR);
   if(h==INVALID_HANDLE){ Print("创建 testWPR 出错"); class="kw">return(INIT_FAILED);}
   h1 = iCustom(NULL,class="num">0,"testWPRjpy",WPR);
   if(h1==INVALID_HANDLE){ Print("创建 testWPRjpy 出错"); class="kw">return(INIT_FAILED);}
   ArraySetAsSeries(ind,true);
   SetIndexBuffer(class="num">0,ind);
   IndicatorSetString(INDICATOR_SHORTNAME,"testWPRdistance");
   IndicatorSetInteger(INDICATOR_DIGITS,class="num">2);
   IndicatorSetInteger(INDICATOR_LEVELS,class="num">2);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,class="num">0,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,class="num">1,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,class="num">0,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,class="num">1,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,class="num">0,class="num">1);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,class="num">1,class="num">1);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,class="num">0,-class="num">60);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,class="num">1,class="num">60);
   PlotIndexSetInteger(class="num">0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(class="num">0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(class="num">0,PLOT_LINE_WIDTH,class="num">2);
   PlotIndexSetInteger(class="num">0,PLOT_LINE_COLOR,clr);
   PlotIndexSetString(class="num">0,PLOT_LABEL,"_tstWPRdistance_");
   ArraySetAsSeries(ma,true);
   SetIndexBuffer(class="num">1,ma);
   PlotIndexSetInteger(class="num">1,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(class="num">1,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(class="num">1,PLOT_LINE_WIDTH,class="num">1);
   PlotIndexSetInteger(class="num">1,PLOT_LINE_COLOR,clrMA);
   PlotIndexSetString(class="num">1,PLOT_LABEL,"Middle_Basket_line_MA");
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class="type">class="kw">double GetValue(class="type">int shift)
  {
   class="type">class="kw">double dBuf[class="num">1],dBuf1[class="num">1];
   class="type">class="kw">double res=class="num">0.0;
   CopyBuffer(h,class="num">0,shift,class="num">1,dBuf);
   CopyBuffer(h1,class="num">0,shift,class="num">1,dBuf1);
   class="kw">return(NormalizeDouble((dBuf[class="num">0]-dBuf1[class="num">0])/class="num">2,_Digits));
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自定义指标迭代函数                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(class="kw">const class="type">int rates_total,
                class="kw">const class="type">int prev_calculated,
                class="kw">const class="type">class="kw">datetime &time[],
                class="kw">const class="type">class="kw">double &open[],
                class="kw">const class="type">class="kw">double &high[],
                class="kw">const class="type">class="kw">double &low[],
                class="kw">const class="type">class="kw">double &close[],
                class="kw">const class="type">long &tick_volume[],
                class="kw">const class="type">long &volume[],
                class="kw">const class="type">int &spread[])
  {
   if(prev_calculated==class="num">0 || rates_total>prev_calculated+class="num">1)
     {
      class="type">int rt=rates_total-WPR;
      for(class="type">int i=class="num">1;i<rt;i++)
        {
         ind[i]=GetValue(i);
        }
      rt -= maperiod;
      for(class="type">int i=class="num">1;i<rt;i++)
        {
         ma[i]=GetMA(ind,i,maperiod,_Digits);
        }
     }
   else
     {
     }
class=class="str">"cmt">//--- 返回 prev_calculated 值用于下次调用
   class="kw">return(rates_total);
  }
class="type">void OnDeinit(class="kw">const class="type">int reason)
  {
   IndicatorRelease(h);
   IndicatorRelease(h1);
   class="type">class="kw">string text;
   class="kw">switch(reason)
     {
      case REASON_PROGRAM: text="指标通过调用 ExpertRemove() 函数终端其操作"; class="kw">break;
      case REASON_INITFAILED: text="此值意味着 OnInit() 处理器 "+__FILE__+" 已返回一个非零值"; class="kw">break;
      case REASON_CLOSE: text="终端已关闭"; class="kw">break;
      case REASON_ACCOUNT: text="账户已改变"; class="kw">break;
      case REASON_CHARTCHANGE: text="品种或时间帧已改变"; class="kw">break;
      case REASON_CHARTCLOSE: text="图表已关闭"; class="kw">break;
      case REASON_PARAMETERS: text="输入参数已变更"; class="kw">break;
      case REASON_RECOMPILE: text="程序 "+__FILE__+" 已编译"; class="kw">break;
      case REASON_REMOVE: text="程序 "+__FILE__+" 已从图表上移除"; class="kw">break;
      case REASON_TEMPLATE: text="新模板已应用于图表"; class="kw">break;
      class="kw">default:text="其它原因";
     }
   PrintFormat("%s",text);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double GetMA(class="kw">const class="type">class="kw">double &arr[],class="type">int index,class="type">int period,class="type">int digit)
{
   class="type">class="kw">double m=class="num">0;
   for(class="type">int j=class="num">0;j<period;j++) m+=arr[index+j];
   m/=period;
   class="kw">return(NormalizeDouble(m,digit));
}
让小布替你重标定指标
这些WPR重标定与篮子形态诊断,小布盯盘的AIGC已内置,打开对应品种页即可看到实时组合状态,你只管判断信号真假。

常见问题

原生范围在显示篮子合并后的极端强弱时会截断边界形态,扩展过零后上下边界对称,才能完整呈现动态入场信号。
可以,小布会标记组合WPR高于90%或低于-90%的极值区,并叠加价格行为提示,帮你过滤假反转。
形态1是趋势跟随反转信号,权威做法要求等蜡烛收盘确认,动态执行容易在假突破上吃亏,作者明确不推荐。
形态5依赖均线斜率与WPR背离,偏中短周期篮子效果更清晰,长周期易受单一货币基本面扰动。