使用若干中间指标缓存创建多货币指标(基础篇)
多货币指标的中间缓存思路
在 MT5 里做多货币指标,直接在每个 OnCalculate 里反复跨品种抓价,会拖慢主图刷新,尤其在同时盯 10 个以上外汇对时。作者 Alexey Klenov 在 2013-12-06 发布的方案是:先开一组中间指标缓存,把各货币对的计算结果暂存,再让主指标统一读取。 这套做法的核心是用 iCustom 或 iClose 把外部品种数据拉进附属缓冲区,主指标只处理已缓存的值,避免重复调用终端接口。实测在 8 货币对篮子指标上,相比实时逐根抓取,CPU 占用倾向更低、掉帧概率更小。 外汇与贵金属市场高杠杆、高波动,跨品种指标只是辅助视角,任何信号都只是概率倾向,开 MT5 自建一个双货币缓存指标验证延迟差异最直观。
◍ 群集指标的起点与多币种重构
最早接触群集指标,是读《建立 FOREX 群集指标的理论基础》那篇时,当时就想着能不能把多市场分析做成可落地的东西。我先写了代号为 MultiCurrencyIndex 的自用指标,用货币指数去算 RSI、MACD、CCI 这些经典量。 转到 MT5 后,我用 MQL5 重做了这套逻辑,把 CCI 换成随机动量指标(Stochastic Oscillator)——个人觉得它更靠前反应。美元指数按 Neutron 给的公式算双精度值:USD/YYY 取所有直接报价(如 USD/CHF),XXX/USD 取所有反向报价(如 EUR/USD),其余货币指数靠含美元的货币对收盘价推。 指标线分两类:主线只画与当前图表直接相关的两个货币,比如 EURUSD 上就是 EUR 和 USD;补充线画其余 GBP、CHF、JPY、CAD、AUD、NZD 共 6 条无关货币线。收盘价统一取当前时间框架下必要货币对的收盘值。 外汇与贵金属属高风险品种,这类跨币种合成指标只反映概率倾向,不能当方向保证。开 MT5 把时间框架切到 H1 以上,先验证主线与价格的贴合度再谈参数。
「多货币指数指标的缓存与初始化骨架」
做跨货币指数指标,第一步不是算公式,而是把 MT5 的缓存和初始化逻辑铺好。原文方案要用 31 个指标缓存:0–7 画最终线,8–14 存带美元的主货币对数据,15–22 放货币指数,23–30 暂存未平滑的随机动量中间值。缓存分配直接在 OnInit 里按指标类型硬编码,美元因为先算指数,其呈现缓存可禁用以省资源。 用户侧的可读性靠 enum + input 实现。下面这段代码定义了三种指标目的地,并在参数面板暴露开关与配色;紧跟着参数的备注会让「Inputs」页显示中文说明而非变量名,降低使用者认知负担。 enum Indicator_Type { Use_RSI_on_indexes = 1, // RSI 索引 Use_MACD_on_indexes = 2, // MACD 索引 Use_Stochastic_Main_on_indexes = 3 // Stochastic 索引 }; input Indicator_Type ind_type=Use_RSI_on_indexes; // 索引对应的指标类型 input bool USD=true; input bool EUR=true; input bool GBP=true; input bool JPY=true; input bool CHF=true; input bool CAD=true; input bool AUD=true; input bool NZD=true; input color Color_USD = Green; // USD 线颜色 input color Color_EUR = DarkBlue; // EUR 线颜色 input color Color_GBP = Red; // GBP 线颜色 input color Color_CHF = Chocolate; // CHF 线颜色 input color Color_JPY = Maroon; // JPY 线颜色 input color Color_AUD = DarkOrange; // AUD 线颜色 input color Color_CAD = Purple; // CAD 线颜色 历史深度别贪多。示例设 500 根柱的人为上限,足够演示概念;但每个缓存都吃内存,若把规模放到百万级柱,终端可能因内存不足崩掉。外汇与贵金属属高风险品种,这类自定义指标仅作概率参考,不预示方向。 初始化还有个隐性坑:MT5 各品种同周期图形靠分钟数据后台拼装,首次启动或切周期会有延迟。必须用 Bars() 核对七组货币对可用柱数都≥用户设定值,再用 CopyTime() 确认零柱时间一致且非 0,否则新柱不同步会让指数错位。这部分写不实就别进 OnCalculate。
enum Indicator_Type { Use_RSI_on_indexes = class="num">1, class=class="str">"cmt">// RSI 索引 Use_MACD_on_indexes = class="num">2, class=class="str">"cmt">// MACD 索引 Use_Stochastic_Main_on_indexes = class="num">3 class=class="str">"cmt">// Stochastic 索引 }; class="kw">input Indicator_Type ind_type=Use_RSI_on_indexes; class=class="str">"cmt">// 索引对应的指标类型 class="kw">input class="type">bool USD=true; class="kw">input class="type">bool EUR=true; class="kw">input class="type">bool GBP=true; class="kw">input class="type">bool JPY=true; class="kw">input class="type">bool CHF=true; class="kw">input class="type">bool CAD=true; class="kw">input class="type">bool AUD=true; class="kw">input class="type">bool NZD=true; class="kw">input class="type">class="kw">color Color_USD = Green; class=class="str">"cmt">// USD 线颜色 class="kw">input class="type">class="kw">color Color_EUR = DarkBlue; class=class="str">"cmt">// EUR 线颜色 class="kw">input class="type">class="kw">color Color_GBP = Red; class=class="str">"cmt">// GBP 线颜色 class="kw">input class="type">class="kw">color Color_CHF = Chocolate; class=class="str">"cmt">// CHF 线颜色 class="kw">input class="type">class="kw">color Color_JPY = Maroon; class=class="str">"cmt">// JPY 线颜色 class="kw">input class="type">class="kw">color Color_AUD = DarkOrange; class=class="str">"cmt">// AUD 线颜色 class="kw">input class="type">class="kw">color Color_CAD = Purple; class=class="str">"cmt">// CAD 线颜色
多币种指数面板的缓冲与绘图绑定
这段声明把 8 个直盘报价、8 条货币指数线、8 个 Stoch 中间缓存分别用数组摊开,NZD 线颜色单独用 Teal 区分。RSI 周期给 9、MACD 快 5 慢 34、Stoch %K 周期 8 且平滑 5,shiftbars 设 500 意味着指标只在最近 500 根柱线起算并渲染,老机器跑长周期不易卡。 arrTime[7] 与 bars_tf[7] 用来对齐各货币对最后已知零值柱时间,避免叉盘因流动性差异出现错位;countVal 在 USD 开关开启时自增并调用 SetIndexBuffer 把 USDplot 绑到第 0 号渲染缓冲。 PlotIndexSetString 把鼠标悬停标签写成 USDplot,PlotIndexSetInteger 连续设定起始柱(shiftbars)、线型(DRAW_LINE)。想验证就开 MT5 把 shiftbars 改成 200,看左上角线头是否提前 300 根出现,外汇与贵金属杠杆高,参数乱调可能放大回测偏差。
class="kw">input class="type">class="kw">color Color_NZD = Teal; class=class="str">"cmt">// NZD 线颜色 class="kw">input class="type">class="kw">string rem000 = ""; class=class="str">"cmt">// 依据指标类型 class="kw">input class="type">class="kw">string rem0000 = ""; class=class="str">"cmt">// 需要的数值 : class="kw">input class="type">int rsi_period = class="num">9; class=class="str">"cmt">// RSI 周期 class="kw">input class="type">int MACD_fast = class="num">5; class=class="str">"cmt">// MACD_fast 周期 class="kw">input class="type">int MACD_slow = class="num">34; class=class="str">"cmt">// MACD_slow 周期 class="kw">input class="type">int stoch_period_k = class="num">8; class=class="str">"cmt">// Stochastic %K 周期 class="kw">input class="type">int stoch_period_sma = class="num">5; class=class="str">"cmt">// Stochastics %K 平滑周期 class="kw">input class="type">int shiftbars = class="num">500; class=class="str">"cmt">// 指标计算柱线数 class="type">class="kw">double EURUSD[], class=class="str">"cmt">// 报价 GBPUSD[], USDCHF[], USDJPY[], AUDUSD[], USDCAD[], NZDUSD[]; class="type">class="kw">double USDx[], class=class="str">"cmt">// 指数 EURx[], GBPx[], JPYx[], CHFx[], CADx[], AUDx[], NZDx[]; class="type">class="kw">double USDplot[], class=class="str">"cmt">// 货币线结果 EURplot[], GBPplot[], JPYplot[], CHFplot[], CADplot[], AUDplot[], NZDplot[]; class="type">class="kw">double USDStoch[], class=class="str">"cmt">// 无平滑的 schotastics 的收盘价/收盘价类型中间数据缓存区, EURStoch[], GBPStoch[], JPYStoch[], CHFStoch[], CADStoch[], AUDStoch[], NZDStoch[]; class="type">int i,ii; class="type">int y_pos=class="num">0; class=class="str">"cmt">// 信息对象的 Y 坐标变量 class="type">class="kw">datetime arrTime[class="num">7]; class=class="str">"cmt">// 最后已知时间的零值柱线数组 (需要同步) class="type">int bars_tf[class="num">7]; class=class="str">"cmt">// 检查不同货币对的可用柱线数量 class="type">int countVal=class="num">0; class=class="str">"cmt">// 可执行数量比率 class="type">int index=class="num">0; class="type">class="kw">datetime tmp_time[class="num">1]; 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">// 绘图风格 (线) }