使用若干中间指标缓存创建多货币指标·进阶篇
🧮

使用若干中间指标缓存创建多货币指标·进阶篇

(2/3)· 跨 7 个货币对拉取收盘价并铺进 31 个缓存,多数人多开图表却从没算清过美元指数

实战向 第 2/3 篇
直接在 EURUSD 图表上裸跑 RSI 却以为看到了欧元强弱,是常见误判。多货币分析若不同步七对报价、不隔离中间缓存,主线与补充线会互相污染。本篇先把缓存骨架搭对,后面的信号才有意义。

「美元指数线的绘制与缓冲绑定」

在 MT5 自定义指标里,把美元相关曲线画出来并不只是调个颜色。先用 SetIndexBuffer 把计算数组(如 USDx 绑到 15 号缓冲)和显示数组(USDplot 绑到 0 号缓冲)分开,计算缓冲设 INDICATOR_CALCULATIONS 不会在窗口露出,显示缓冲设 INDICATOR_DATA 才真正渲染。 数组初始化有两步不能省:ArraySetAsSeries 置为 true 才能按时间倒序索引最新 K 线,ArrayInitialize 填 EMPTY_VALUE 避免残留零值干扰画线。实测若漏掉后者,欧元美元这类品种可能在历史栏出现贴地直线。 绘图属性靠 PlotIndexSetInteger 堆出来:PLOT_DRAW_TYPE 设 DRAW_LINE,PLOT_DRAW_BEGIN 用 shiftbars 控制从第几根柱开始画,PLOT_LABEL 给鼠标悬停名。下面这段逻辑还按品种名动态换样式——名称含 USD 的主图线加宽,其余走细虚线。 若切到随机指标模式(ind_type==Use_Stochastic_Main_on_indexes),需额外开 23 号计算缓冲 USDstoch 存中间值,同样走时间序列初始化。外汇与贵金属波动剧烈,这类多缓冲指标仅作参考,实盘请自担高风险。

MQL5 / C++
PlotIndexSetInteger(class="num">0,PLOT_LINE_COLOR,Color_USD);            class=class="str">"cmt">// 线的渲染颜色
if(StringFind(Symbol(),"USD",class="num">0)!=-class="num">1)
   {PlotIndexSetInteger(class="num">0,PLOT_LINE_WIDTH,wid_main);}            class=class="str">"cmt">// 如果交易品种名称包括 USD
                                                                 class=class="str">"cmt">// 则画适当宽度的线 
   else
   {PlotIndexSetInteger(class="num">0,PLOT_LINE_STYLE,style_slave);}
ArraySetAsSeries(USDplot,true);                                  class=class="str">"cmt">// 按时间序列检索数组  
ArrayInitialize(USDplot,EMPTY_VALUE);                            class=class="str">"cmt">// 零值 
f_draw("USD",Color_USD);                                         class=class="str">"cmt">// 在指标信息窗口渲染 
}
SetIndexBuffer(class="num">15,USDx,INDICATOR_CALCULATIONS);                 class=class="str">"cmt">// 计算美元指数的数组
                                                                 class=class="str">"cmt">// (在指标中不会显示) 
ArraySetAsSeries(USDx,true);                                     class=class="str">"cmt">// 按时间序列检索数组
ArrayInitialize(USDx,EMPTY_VALUE);                               class=class="str">"cmt">// 零值
if(ind_type==Use_Stochastic_Main_on_indexes)
  {
  SetIndexBuffer(class="num">23,USDstoch,INDICATOR_CALCULATIONS);           class=class="str">"cmt">// 如果指标是 Use_Stochastic_Main_on_indexes,
                                                                 class=class="str">"cmt">// 则需要中间数组
  ArraySetAsSeries(USDstoch,true);                              class=class="str">"cmt">// 按时间序列检索数组
  ArrayInitialize(USDstoch,EMPTY_VALUE);                        class=class="str">"cmt">// 零值
  }
if(USD)
  {
  countVal++;
  SetIndexBuffer(class="num">0,USDplot,INDICATOR_DATA);                     class=class="str">"cmt">// 渲染数组
  PlotIndexSetString(class="num">0,PLOT_LABEL,"USDplot");                   class=class="str">"cmt">// 指标线名称 (当鼠标选择时)
  PlotIndexSetInteger(class="num">0,PLOT_DRAW_BEGIN,shiftbars);             class=class="str">"cmt">// 从哪里,我们开始渲染
  PlotIndexSetInteger(class="num">0,PLOT_DRAW_TYPE,DRAW_LINE);              class=class="str">"cmt">// 绘图风格 (线)
  PlotIndexSetInteger(class="num">0,PLOT_LINE_COLOR,Color_USD);             class=class="str">"cmt">// 线的渲染颜色
  if(StringFind(Symbol(),"USD",class="num">0)!=-class="num">1)

美元欧元双线缓冲区的初始化套路

在自定义指标里同时渲染美元与欧元强度线,核心是先给计算数组和绘图数组分别绑定缓冲区。USDx 用编号 15 挂到 INDICATOR_CALCULATIONS,仅参与运算不在副图露出;USDplot 才是真正画出来的线,靠 f_draw("USD",Color_USD) 丢进指标信息窗。 数组必须按时间序列倒序取数,所以每个缓冲都跑一遍 ArraySetAsSeries(...,true),再用 ArrayInitialize 填 EMPTY_VALUE 清零,否则历史柱上可能残留上一轮计算的脏值。 当模式切到 Use_Stochastic_Main_on_indexes,美元线还要多开一个编号 23 的中间数组 USDstoch 承接随机指标主值,这一步漏掉会导致编译通过但运行时数组越界。 欧元线走的是 INDICATOR_DATA 直绘通道:编号 1 绑定 EURplot,PLOT_LABEL 设成 "EURplot" 方便鼠标悬停识别,PLOT_DRAW_BEGIN 用 shiftbars 控制起画位移。若当前品种名含 "EUR"(StringFind 返回非 -1),线宽自动切到 wid_main,让主交易品种在图上更跳。外汇与贵金属波动剧烈,这类多线指标只作参考,实盘仍属高风险。

MQL5 / C++
PlotIndexSetInteger(class="num">0,PLOT_LINE_WIDTH,wid_main); class=class="str">"cmt">// 如果交易品种名称包括 USD 则画适当宽度的线 
else
 {PlotIndexSetInteger(class="num">0,PLOT_LINE_STYLE,style_slave);}
 ArraySetAsSeries(USDplot,true); class=class="str">"cmt">// 按时间序列检索数组
 ArrayInitialize(USDplot,EMPTY_VALUE); class=class="str">"cmt">// 零值 
 f_draw("USD",Color_USD); class=class="str">"cmt">// 在指标信息窗口渲染 
}
SetIndexBuffer(class="num">15,USDx,INDICATOR_CALCULATIONS); class=class="str">"cmt">// 计算美元指数的数组 (在指标中不会显示) 
ArraySetAsSeries(USDx,true); class=class="str">"cmt">// 按时间序列检索数组
ArrayInitialize(USDx,EMPTY_VALUE); class=class="str">"cmt">// 零值
if(ind_type==Use_Stochastic_Main_on_indexes)
 {
 SetIndexBuffer(class="num">23,USDstoch,INDICATOR_CALCULATIONS); class=class="str">"cmt">// 如果指标是 Use_Stochastic_Main_on_indexes, 则需要中间数组
 ArraySetAsSeries(USDstoch,true); class=class="str">"cmt">// 按时间序列检索数组
 ArrayInitialize(USDstoch,EMPTY_VALUE); class=class="str">"cmt">// 零值
 }
if(EUR)
 {
 countVal++;
 SetIndexBuffer(class="num">1,EURplot,INDICATOR_DATA); class=class="str">"cmt">// 渲染数组
 PlotIndexSetString(class="num">1,PLOT_LABEL,"EURplot"); class=class="str">"cmt">// 指标线名称 (当鼠标选择时)
 PlotIndexSetInteger(class="num">1,PLOT_DRAW_BEGIN,shiftbars); class=class="str">"cmt">// 从哪里,我们开始渲染
 PlotIndexSetInteger(class="num">1,PLOT_DRAW_TYPE,DRAW_LINE); class=class="str">"cmt">// 绘图风格 (线)
 PlotIndexSetInteger(class="num">1,PLOT_LINE_COLOR,Color_EUR); class=class="str">"cmt">// 线的渲染颜色
 if(StringFind(Symbol(),"EUR",class="num">0)!=-class="num">1)
 {PlotIndexSetInteger(class="num">1,PLOT_LINE_WIDTH,wid_main);} class=class="str">"cmt">// 如果交易品种名称包括 EUR

◍ EUR 索引缓冲与跨品种函数声明

这段初始化逻辑只服务于 EUR 相关索引的计算与绘图。先判断交易品种名是否含 EUR,不含则用 PlotIndexSetInteger 把第 1 号线改成 style_slave 风格,用于在上方交叉时画辅助线。 EURplot、EURUSD、EURx 三个数组都走 ArraySetAsSeries(...,true) 按时间序列倒序检索,再用 ArrayInitialize 填 EMPTY_VALUE 清零。其中 SetIndexBuffer 把 EURUSD 绑到 8 号缓冲、EURx 绑到 16 号缓冲,后者仅参与计算不显示。 当 ind_type 等于 Use_Stochastic_Main_on_indexes 时,才额外开 24 号缓冲 EURstoch 存中间随机值,同样倒序加清零。最后 f_draw("EUR",Color_EUR) 把结果渲到指标窗口。 下方是一组被调用的函数原型:f_RSI、f_MACD、SimpleMA、f_Stoch 负责各类指标计算,f_draw 与 f_comment 管渲染和文字,Bars 则按 symbol_name 与 timeframe 取 BAR 数。复制进 MT5 的 include 区即可直接编译验证。

MQL5 / C++
else
   {PlotIndexSetInteger(class="num">1,PLOT_LINE_STYLE,style_slave);}
ArraySetAsSeries(EURplot,true);
ArrayInitialize(EURplot,EMPTY_VALUE);
SetIndexBuffer(class="num">8,EURUSD,INDICATOR_CALCULATIONS);
ArraySetAsSeries(EURUSD,true);
ArrayInitialize(EURUSD,EMPTY_VALUE);
SetIndexBuffer(class="num">16,EURx,INDICATOR_CALCULATIONS);
ArraySetAsSeries(EURx,true);
ArrayInitialize(EURx,EMPTY_VALUE);
if(ind_type==Use_Stochastic_Main_on_indexes)
   {
      SetIndexBuffer(class="num">24,EURstoch,INDICATOR_CALCULATIONS);
      ArraySetAsSeries(EURstoch,true);
      ArrayInitialize(EURstoch,EMPTY_VALUE);
   }
f_draw("EUR",Color_EUR);
}
class="type">class="kw">double f_RSI(class="type">class="kw">double &buf_in[], class="type">int period,class="type">int shift),
class="type">class="kw">double f_MACD(class="type">class="kw">double &buf_in[], class="type">int period_fast,class="type">int period_slow,class="type">int shift),
class="type">class="kw">double SimpleMA(const class="type">int position,const class="type">int period,const class="type">class="kw">double &price[]),
class="type">class="kw">double f_Stoch(class="type">class="kw">double &price[], class="type">int period_k, class="type">int shift),
class="type">int f_draw(class="type">class="kw">string name, class="type">class="kw">color _color)
class="type">int f_comment(class="type">class="kw">string text)
class="type">int  Bars(
   class="type">class="kw">string          symbol_name,   class=class="str">"cmt">// 交易品种名称
   ENUM_TIMEFRAMES  timeframe     class=class="str">"cmt">// 周期
   );

「美元指数合成的计算循环怎么写」

指标主函数 OnCalculate 拿到 MT5 推送的 rates_total 与 prev_calculated,用来判断是首次算还是增量刷。prev_calculated 大于 0 时只跑最新一根(limit=1),否则从 shiftbars 根起步,这是避免每 tick 重算全量的关键。 多币种收盘价通过 CopyClose 拉进各自数组,任一个返回 -1 就 f_comment 提示并 return(0),等于说数据没齐绝不瞎算。EURUSD、GBPUSD 直接加,USDCHF、USDJPY、USDCAD 取倒数再加,因为后者报价是「单位外币合多少美元」,倒过来才是美元视角。 循环从 limit-1 向下到 0,USDx[i] 初值 1.0 再累加各货币对贡献。外汇与贵金属波动受美元指数牵引明显,这类合成指数在重大数据夜跳变概率偏高,实盘使用前建议在策略测试器用至少 3 个月 tick 验证一次权重偏差。

MQL5 / C++
class="type">int OnCalculate(const class="type">int     rates_total, class=class="str">"cmt">// 输入时间序列大小
                const class="type">int     prev_calculated, class=class="str">"cmt">// 前一次请求处理的柱线
                const class="type">class="kw">datetime&    time[], class=class="str">"cmt">// 开盘时间
                const class="type">class="kw">double&      open[], class=class="str">"cmt">// 开盘价
                const class="type">class="kw">double&      high[], class=class="str">"cmt">// 最高价
                const class="type">class="kw">double&       low[], class=class="str">"cmt">// 最低价
                const class="type">class="kw">double&     close[], class=class="str">"cmt">// 收盘价
                const class="type">long& tick_volume[], class=class="str">"cmt">// 即时交易量
                const class="type">long&      volume[], class=class="str">"cmt">// 实际交易量
                const class="type">int&       spread[]  class=class="str">"cmt">// 点差
                );
 class="type">int limit=shiftbars;
 if(prev_calculated>class="num">0)
    {limit=class="num">1;}
 else
    {limit=shiftbars;}
 init_tf();
 if (EUR){copied=CopyClose("EURUSD",PERIOD_CURRENT,class="num">0,shiftbars,EURUSD); if (copied==-class="num">1){f_comment("等待...EURUSD");class="kw">return(class="num">0);}}
 if (GBP){copied=CopyClose("GBPUSD",PERIOD_CURRENT,class="num">0,shiftbars,GBPUSD); if (copied==-class="num">1){f_comment("等待...GBPUSD");class="kw">return(class="num">0);}}
 if (CHF){copied=CopyClose("USDCHF",PERIOD_CURRENT,class="num">0,shiftbars,USDCHF); if (copied==-class="num">1){f_comment("等待...USDCHF");class="kw">return(class="num">0);}}
 if (JPY){copied=CopyClose("USDJPY",PERIOD_CURRENT,class="num">0,shiftbars,USDJPY); if (copied==-class="num">1){f_comment("等待...USDJPY");class="kw">return(class="num">0);}}
 if (AUD){copied=CopyClose("AUDUSD",PERIOD_CURRENT,class="num">0,shiftbars,AUDUSD); if (copied==-class="num">1){f_comment("等待...AUDUSD");class="kw">return(class="num">0);}}
 if (CAD){copied=CopyClose("USDCAD",PERIOD_CURRENT,class="num">0,shiftbars,USDCAD); if (copied==-class="num">1){f_comment("等待...USDCAD");class="kw">return(class="num">0);}}
 if (NZD){copied=CopyClose("NZDUSD",PERIOD_CURRENT,class="num">0,shiftbars,NZDUSD); if (copied==-class="num">1){f_comment("等待...NZDUSD");class="kw">return(class="num">0);}} 
for (i=limit-class="num">1;i>=class="num">0;i--)
  {
     class=class="str">"cmt">//计算美元指数
     USDx[i]=class="num">1.0;
     if (EUR){USDx[i]+=EURUSD[i];}       
     if (GBP){USDx[i]+=GBPUSD[i];}
     if (CHF){USDx[i]+=class="num">1/USDCHF[i];}
     if (JPY){USDx[i]+=class="num">1/USDJPY[i];}
     if (CAD){USDx[i]+=class="num">1/USDCAD[i];}
让小布替你跑这套
这些跨货币缓存同步与指数计算,小布盯盘的 AIGC 已内置,打开对应品种页即可看到主线与补充线的实时分离,你只管读背离。

常见问题

0-7 用于最终呈现线,8-14 存含美元货币对,15-22 存货币指数,分层隔离才能避免重算与越界写值。
用 CopyClose 按符号名拉取指定周期收盘价写入对应缓存,注意处理品种不存在或历史不足返回的空句柄。
随机动量对拐点更敏感、倾向提前反应,但噪声也更高,需配合主线过滤假交叉。
可以,小布盯盘品种页内置了跨货币指数分离视图,省去自己写 31 缓存的麻烦,外汇贵金属波动剧烈仍属高风险。
USD/CHF 类为直接、EUR/USD 类为反向,分别进 8-14 缓存的不同偏移位,再按加权公式合成美元指数。