交易货币篮子形态·基础篇:用 WPR 重构看清篮子强弱信号(基础篇)
(1/3)·多数人盯单一货币对却亏在篮子联动,本文先铺术语与指标改造底层的逻辑
◍ 货币篮子里的形态识别起点
在 MT5 中做货币篮子交易,形态识别不能只盯单一图表。把若干相关性弱的货币对放进一个观察组,同一类价格行为会在不同品种上同步或错位出现,这比单品种信号更有参考价值。 原文作者 Andrei Novichkov 在 2017 年 2 月 2 日发布该主题,截至统计显示阅读量 6 658、收藏 9,说明篮子交易形态在早期就有人气积累。 实操上,先开 MT5 的「市场观察」右键添加一组主要货币对,切到相同周期(如 H1),用肉眼或脚本扫「双顶 / 双底 / 旗形」是否跨品种共现。若出现 3 个以上品种同形态,该篮子方向倾向有更高确认度,但外汇与贵金属属高风险,跨品种共振也可能被突发事件打断。
「把 WPR 改造成篮子专用尺」
做货币篮子不能只靠之前讲的原则和术语,入场离场信号才是能不能跑通的关键。本文目标很直接:把处理篮子时已形成的、能明显抬升盈利概率的形态拆清楚,术语沿用之前那套篮子与技术工具定义。 分析篮子状态用威廉姆斯百分比范围(WPR)。原版 WPR 数值落在 0% 到 -100%,对篮子形态识别不够用——正确显示全部形态要求数值区间扩到 100% 到 -100%,这个改动在指标代码里改几行就能完成。 原版超卖/超买阈值在合并后的区间里依然有效,我们会直接拿来用。你在 MT5 里打开 WPR 源码,把 UpperBuffer 和 LowerBuffer 的映射改掉,就能验证区间扩展后形态是否更完整。外汇与贵金属篮子组合波动叠加,属高风险玩法,改参数前先开模拟盘跑一遍。
动态入场的两种篮子形态陷阱
动态入场指的是指标信号触达特定阈值就下单,不等当前 K 线收线。以货币篮子 WPR 为例,当组合读数逼近区间上沿或下沿(比如 ±90% 以外),往往对应某币种因事件驱动被集中买压或卖压。此时若按动态逻辑入场,等于赌反转或延续会在信号点立刻发生。 形态 #1 是教科书里最常见的:指标几乎触碰边界后反向突破超买/超卖线,被当作篮子内全部货币的趋势跟随信号。权威资料几乎一致反对动态执行这类入场,实盘里追边界反转的滑点和假突破概率都不友好,不建议采用。 形态 #2 是它的逆势改版:指标贴近边界却随原趋势再反转,试图抓趋势起点。WPR 本就不是趋势指标,能在边界外徘徊很久只微偏再贴近。2015 年 1 月瑞郎黑天鹅前后,H1 读数在 12:51:32 达到 99.16、H4 99.17、D1 99.17,两秒后降到 98.85 附近,反复贴近边界——任何这时动态逆势接刀的人基本秒触止损。 有些交易者只在读数高于 90% 或低于 -90% 才用形态 #2,并辅以价格行为确认,且避开刚出的基本面消息、只在已成趋势里找末端迹象。但失败率奇高,外汇与贵金属杠杆环境下这种逆势动态入场风险极大,我也不推荐。
◍ 收盘后再确认信号,篮子交易别踩限价坑
组合 WPR 在母指标基础上做了归一:区间仍是 -100% 到 100%,但超买线划在 60%、超卖线在 -60%,而非单货币 WPR 常见的 -20% / -80%。只有当当前时间帧蜡烛完全收盘,组合线向下穿越 60% 或向上穿越 -60%,才把篮子内全部货币对视为同向下单信号——这根收盘棒是形态 #3 不可省略的过滤器。 顺带注意,边界突破往往伴生指标在极值附近的反转,意味着一段虽短但真实的价格摆动,所以信号本质是顺这一摆动入场。下单可用市价,也可挂限价;但篮子单若用限价,窗口内未必每对都触价。 实战里容易吃暗亏:比如 EUR 篮子组合线从 -60% 下方反转向上,你买多欧元篮子,可 EURJPY 因紧接着出日元利好,日元涨得比欧元快,这对反而走平甚至拐跌。若限价单只触发了 EURJPY 这一对,整体就是亏的,其他无新消息的欧系叉盘盈利也没接上。外汇与贵金属属高风险品种,篮子信号不代表每对必同向。 下面这段 MT5 指标把 7 个欧系对 WPR(14) 等权平均再映射到 ±100 区间,可直接拖到 H1 验证上面说的级别位置。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| testWPR.mq5 | class=class="str">"cmt">//| MetaQuotes 软件公司| class=class="str">"cmt">//| http://fxstill.com | 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">1 class="macro">#class="kw">property indicator_plots class="num">1 input class="type">int WPR= class="num">14 ; class=class="str">"cmt">// WRP 周期 input class="type">color clr= clrBlue ; class="macro">#define LG class="num">7 class="type">class="kw">string pair[]={ "EURUSD" , "EURJPY" , "EURCHF" , "EURGBP" , "EURNZD" , "EURCAD" , "EURAUD" }; class="type">int h[LG]; class="type">class="kw">double ind[]; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 指标缓存区映射 for ( class="type">int i= class="num">0 ; i<LG; i++) { h[i]= iWPR(pair[i], class="num">0 ,WPR); } ArraySetAsSeries(ind, true ); SetIndexBuffer( class="num">0 ,ind); IndicatorSetString( INDICATOR_SHORTNAME , "testWPR" ); 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 , "_tstWPR_" ); class=class="str">"cmt">//--- class="kw">return ( INIT_SUCCEEDED ); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double GetValue( class="type">int shift) { class="type">class="kw">double dBuf[ class="num">1 ]; class="type">class="kw">double res= class="num">0.0 ; for ( class="type">int i= class="num">0 ; i<LG; i++) { CopyBuffer(h[i], class="num">0 ,shift, class="num">1 ,dBuf); res+=dBuf[ class="num">0 ]; } class=class="str">"cmt">//结束 for (class="type">int i = class="num">0; i < iCount; i++) res=res/LG; class="kw">return ( NormalizeDouble((res + class="num">50 ) * 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[]) { class=class="str">"cmt">//--- 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 { } class=class="str">"cmt">//--- 返回 prev_calculated 值用于下次调用 class="kw">return (rates_total); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit( class="kw">const class="type">int reason) { for ( class="type">int i= class="num">0 ; i<LG; i++) { if (h[i]!= INVALID_HANDLE ) IndicatorRelease(h[i]); } 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=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| testWPR.mq5 | class=class="str">"cmt">//| MetaQuotes 软件公司| class=class="str">"cmt">//| http://fxstill.com | 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">1 class="macro">#class="kw">property indicator_plots class="num">1 input class="type">int WPR= class="num">14 ; class=class="str">"cmt">// WRP 周期 input class="type">color clr= clrBlue ; class="macro">#define LG class="num">7 class="type">class="kw">string pair[]={ "EURUSD" , "EURJPY" , "EURCHF" , "EURGBP" , "EURNZD" , "EURCAD" , "EURAUD" }; class="type">int h[LG]; class="type">class="kw">double ind[]; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 指标缓存区映射 for ( class="type">int i= class="num">0 ; i<LG; i++) { h[i]= iWPR(pair[i], class="num">0 ,WPR); } ArraySetAsSeries(ind, true ); SetIndexBuffer( class="num">0 ,ind); IndicatorSetString( INDICATOR_SHORTNAME , "testWPR" ); 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 , "_tstWPR_" ); class=class="str">"cmt">//--- class="kw">return ( INIT_SUCCEEDED ); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double GetValue( class="type">int shift) { class="type">class="kw">double dBuf[ class="num">1 ]; class="type">class="kw">double res= class="num">0.0 ; for ( class="type">int i= class="num">0 ; i<LG; i++) { CopyBuffer(h[i], class="num">0 ,shift, class="num">1 ,dBuf); res+=dBuf[ class="num">0 ]; } class=class="str">"cmt">//结束 for (class="type">int i = class="num">0; i < iCount; i++) res=res/LG; class="kw">return ( NormalizeDouble((res + class="num">50 ) * 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[]) { class=class="str">"cmt">//--- 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 { } class=class="str">"cmt">//--- 返回 prev_calculated 值用于下次调用 class="kw">return (rates_total); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit( class="kw">const class="type">int reason) { for ( class="type">int i= class="num">0 ; i<LG; i++) { if (h[i]!= INVALID_HANDLE ) IndicatorRelease(h[i]); } 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">//+------------------------------------------------------------------+