使用若干中间指标缓存创建多货币指标·进阶篇
(2/3)· 跨 7 个货币对拉取收盘价并铺进 31 个缓存,多数人多开图表却从没算清过美元指数
「美元指数线的绘制与缓冲绑定」
在 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 存中间值,同样走时间序列初始化。外汇与贵金属波动剧烈,这类多缓冲指标仅作参考,实盘请自担高风险。
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,让主交易品种在图上更跳。外汇与贵金属波动剧烈,这类多线指标只作参考,实盘仍属高风险。
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 区即可直接编译验证。
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 验证一次权重偏差。
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];}