多品种价格偏离指标开发:从零搭建跨图表分析框架(基础篇)
(1/3)· 面对 1500 行指标代码无从下手?本篇拆开多品种偏离分析的项目结构与事件处理基础
不少交易者在 MT5 里想同时比对多个品种的价格偏离,却卡在图表拖拽事件和缓存区配色上。直接抄旧版多货币指标往往跑不通,因为新需求要处理对象拖拽与图表属性变更。先把工程拆成三个 include 文件,比硬啃主文件更省事。
◍ 用多品种指标抓跨市场偏离
在 MT5 里做价格行为分析,单看一个品种容易漏掉关联市场的异常。把多个品种拉到同一指标窗口,能直观比对它们的相对强弱和偏离程度。 Anatoli Kazharski 在 2014 年 6 月发布的示例显示,这类多品种指标在发布后获得 2417 次查看与 21 条互动,说明跨品种比对是实盘前值得验证的思路。外汇与贵金属跨品种偏离受流动性与突发事件影响,高风险,偏离回归只是概率倾向,不是必然。 打开 MT5 新建自定义指标,把 Symbol() 参数改成可配置的字符串数组,就能在同一副图叠加 EURUSD、XAUUSD 等品种的标准化价格曲线。先跑一遍历史数据,看偏离超过 2 个标准差时后续修复倾向,再决定要不要接警报。
「多品种偏离指标的新架构与事件处理」
这一篇只啃增量:在已有的多品种波动分析框架上,重做一套能分析指定周期价格偏离的指标。老文章讲过基础编程套路,新人先去补那块,本文不重复造轮子。 新指标要落地的几个硬点:改图表属性;响应 CHARTEVENT_OBJECT_DRAG(拖拽对象)和 CHARTEVENT_CHART_CHANGE(属性框缩放/改属性);用多色渲染指标缓存区;在可视区内抓缓存区最高最低来重设图表上下轨;以及序列翻转。 代码量约 1500 行,全塞一个文件没法维护,拆成三个 .mqh 外挂:Checks.mqh 管检查和数据下载,Objects.mqh 管图形对象,Chart.mqh 管图表属性。主文件只留归类不进的杂函数,用 #include 链进来。 外汇与贵金属品种波动剧烈、杠杆风险高,多品种同屏偏离只是概率性参考,别当方向指令。
多品种价格叠加指标的缓冲区与绘制架构
在 MT5 里做多品种叠加指标,第一步是在 MQL5\Indicators 下建同名文件夹,主文件用 *.mq5 或向导模板生成;除 OnInit / OnDeinit / OnCalculate 外,本例还挂了 OnChartEvent 与 OnTimer 来处理拖拽垂直线和定时刷新。 只画单色折线时,缓冲区数量等于品种数就够了;但本指标要支持柱线/蜡烛双色模式,每个序列需两个缓冲:一个画序列、一个按条件给元素上色。原文示例用 5 个品种、25 个缓冲区(#property indicator_buffers 25)和 5 个绘图序列(indicator_plots 5),双色靠逗号分隔的第二色渲染阴线。 外部参数用 ENUM_DRAWTYPE(折线/柱线/蜡烛)和 ENUM_START_POINT 做下拉选择。起始点有五种:垂直线、月、周、日、小时。垂直线模式在加载时插一根绿线,拖到某根 K 线后所有品种以该 K 线开盘价汇聚;其余四种则按对应周期开头自动汇聚。 品种数下限是 2(含当前图表的 EURUSD)。对每个非当前品种可设翻转,把 USDCHF 这类同基准货币对上下颠倒后,和 EURUSD 同屏对比更直观。OnInit 里用 CheckTesterMode 拦掉策略测试器(终端尚未支持测市中改图表属性),InitStartPointTF 按选择分配 timeframe_start_point,SetDivergenceLine 在垂线模式放操控线。 OnCalculate 改为单循环填充,并新增 LoadAndFormDataHighTF 取高周期起点时间;FillIndicatorBuffers 拆成取数、定汇聚位、算值填缓冲、校验四步,CorrectChartMaxMin 借可视柱线数重设纵轴最大最小,避免多品种尺度错位。外汇与贵金属叠加对比属高风险分析,结果仅作概率参考。
class="macro">#class="kw">property indicator_chart_window class=class="str">"cmt">// Indicator is in the main window class="macro">#class="kw">property indicator_buffers class="num">25 class=class="str">"cmt">// Number of buffers for indicator calculation class="macro">#class="kw">property indicator_plots class="num">5 class=class="str">"cmt">// Number of plotting series class=class="str">"cmt">//--- Indicator buffers colors class="macro">#class="kw">property indicator_color1 clrDodgerBlue,C&class="macro">#x27;class="num">0,class="num">50,class="num">100&class="macro">#x27; class="macro">#class="kw">property indicator_color2 clrLimeGreen,C&class="macro">#x27;class="num">20,class="num">80,class="num">20&class="macro">#x27; class="macro">#class="kw">property indicator_color3 clrGold,C&class="macro">#x27;class="num">160,class="num">140,class="num">0&class="macro">#x27; class="macro">#class="kw">property indicator_color4 clrAqua,C&class="macro">#x27;class="num">0,class="num">140,class="num">140&class="macro">#x27; class="macro">#class="kw">property indicator_color5 clrMagenta,C&class="macro">#x27;class="num">130,class="num">0,class="num">130&class="macro">#x27; class=class="str">"cmt">//--- Constants class="macro">#define RESET class="num">0 class=class="str">"cmt">// Returning the indicator recalculation command to the terminal class="macro">#define SYMBOLS_COUNT class="num">5 class=class="str">"cmt">// Number of symbols class=class="str">"cmt">//--- Include the class for working with the canvas class="macro">#include <Canvas\Canvas.mqh> class=class="str">"cmt">//--- Include the class for working with the canvas class="macro">#include "Include/Checks.mqh" class="macro">#include "Include/Chart.mqh" class="macro">#include "Include/Objects.mqh" class=class="str">"cmt">//--- Drawing type of the price data enum ENUM_DRAWTYPE { LINE =class="num">0, class=class="str">"cmt">// Line BARS =class="num">1, class=class="str">"cmt">// Bars CANDLES=class="num">2 class=class="str">"cmt">// Candlesticks }; class=class="str">"cmt">//--- Mode of the price divergence starting point enum ENUM_START_POINT {
◍ 多品种叠加的参数与缓冲结构
这段声明定义了指标如何把多个外汇品种塞进同一画面。枚举里 VERTICAL_LINE 到 HOUR 分别对应 0~4 的整数,用来标记价格背离的起始参考粒度,从竖线、月、周、日一直到小时,实战中若只看日内背离,把 StartPriceDivergence 设成 4 即可。 外部参数里 DrawType 控制蜡烛或线形绘制,TwoColor 决定是否用双色区分涨跌;后面从 Symbol02 到 Symbol06 一口气挂了 GBPUSD、AUDUSD、NZDUSD、USDCAD、USDCHF 五个副品种,每个都带 Inverse 开关,置 true 会把该品种走势反向叠加,适合观察负相关性。外汇与贵金属叠加多品种属高风险操作,参数误设可能放大误判。 缓冲结构用 struct 把 open、high、low 三个 double 数组打包,后续每个品种的价格数据就按这个模板写入指标缓冲区,方便统一调度。 让小布替你跑这套 把 Symbol02 改成你常看的 XAUUSD,Inverse02 设 true,加载后若黄金与主线反向运动明显,说明对冲参考有效,可继续加品种验证。
VERTICAL_LINE=class="num">0, class=class="str">"cmt">// Vertical line MONTH =class="num">1, class=class="str">"cmt">// Month WEEK =class="num">2, class=class="str">"cmt">// Week DAY =class="num">3, class=class="str">"cmt">// Day HOUR =class="num">4 class=class="str">"cmt">// Hour }; class=class="str">"cmt">//--- External parameters input ENUM_DRAWTYPE DrawType =CANDLES; class=class="str">"cmt">// Drawing type input ENUM_START_POINT StartPriceDivergence =VERTICAL_LINE; class=class="str">"cmt">// Start of price divergence input class="type">bool TwoColor =false; class=class="str">"cmt">// Two-class="type">color bars/candlesticks sinput class="type">class="kw">string dlm01=""; class=class="str">"cmt">//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - input class="type">class="kw">string Symbol02 ="GBPUSD"; class=class="str">"cmt">// Symbol class="num">2 input class="type">bool Inverse02 =false; class=class="str">"cmt">// Inverse symbol class="num">2 input class="type">class="kw">string Symbol03 ="AUDUSD"; class=class="str">"cmt">// Symbol class="num">3 input class="type">bool Inverse03 =false; class=class="str">"cmt">// Inverse symbol class="num">3 input class="type">class="kw">string Symbol04 ="NZDUSD"; class=class="str">"cmt">// Symbol class="num">4 input class="type">bool Inverse04 =false; class=class="str">"cmt">// Inverse symbol class="num">4 input class="type">class="kw">string Symbol05 ="USDCAD"; class=class="str">"cmt">// Symbol class="num">5 input class="type">bool Inverse05 =false; class=class="str">"cmt">// Inverse symbol class="num">5 input class="type">class="kw">string Symbol06 ="USDCHF"; class=class="str">"cmt">// Symbol class="num">6 input class="type">bool Inverse06 =false; class=class="str">"cmt">// Inverse symbol class="num">6 class=class="str">"cmt">//--- Structure of the indicator buffers arrays class="kw">struct buffers { class="type">class="kw">double open[]; class=class="str">"cmt">// Open prices buffer class="type">class="kw">double high[]; class=class="str">"cmt">// High prices buffer class="type">class="kw">double low[]; class=class="str">"cmt">// Low prices buffer
「多品种指标的内存结构怎么摆」
写跨品种指标时,先把每个交易品种的缓冲区和状态变量按数组组织好,否则 OnCalculate 里很容易乱套。下面这段声明定义了每个符号各自的收盘价缓冲、颜色缓冲,以及统一存一批符号数据的结构体数组 buffer_data[SYMBOLS_COUNT],SYMBOLS_COUNT 决定最多能同时画几个品种。 从 OnCalculate 往全局搬数据,靠的是 OC_ 前缀那组变量:OC_rates_total 记录输入序列长度,OC_prev_calculated 记上次已处理柱数,OC_open/high/low/close 等分别接开高低收和量。用它们做增量计算,能少跑无用循环。 顺手定义了一些易漏的细节:series_first_date 与 series_first_date_last 用来核对终端里首根 K 线的真实时间,limit_time 控制从哪根柱开始画;line_colors 直接给了 5 个颜色(clrDodgerBlue、clrLimeGreen、clrGold、clrAqua、clrMagenta),对应前 5 个品种线色;empty_symbol 设成 "EMPTY" 标记缺品种。外汇贵金属多品种叠加波动相关性强,实盘前请在 MT5 用 3~5 个品种验证内存占用与重绘表现,相关风险偏高。
class="type">class="kw">double close[]; class=class="str">"cmt">// Close prices buffer class="type">class="kw">double icolor[]; class=class="str">"cmt">// Buffer to determine the class="type">color of element }; buffers buffer_data[SYMBOLS_COUNT]; class=class="str">"cmt">//--- Load the class CCanvas canvas; class=class="str">"cmt">//--- Variables/arrays for copying data from OnCalculate() class="type">int OC_rates_total =class="num">0; class=class="str">"cmt">// Size of input time series class="type">int OC_prev_calculated =class="num">0; class=class="str">"cmt">// Bars processed at the previous call class="type">class="kw">datetime OC_time[]; class=class="str">"cmt">// Opening time class="type">class="kw">double OC_open[]; class=class="str">"cmt">// Open prices class="type">class="kw">double OC_high[]; class=class="str">"cmt">// High prices class="type">class="kw">double OC_low[]; class=class="str">"cmt">// Low prices class="type">class="kw">double OC_close[]; class=class="str">"cmt">// Close prices class="type">long OC_tick_volume[]; class=class="str">"cmt">// Tick volumes class="type">long OC_volume[]; class=class="str">"cmt">// Real volumes class="type">int OC_spread[]; class=class="str">"cmt">// Spread class=class="str">"cmt">//--- For the purpose of storing and checking the time of the first bar in the terminal class="type">class="kw">datetime series_first_date[SYMBOLS_COUNT]; class="type">class="kw">datetime series_first_date_last[SYMBOLS_COUNT]; class=class="str">"cmt">//--- Time array of the bar from which we will start drawing class="type">class="kw">datetime limit_time[SYMBOLS_COUNT]; class=class="str">"cmt">//--- Symbol names array class="type">class="kw">string symbol_names[SYMBOLS_COUNT]; class=class="str">"cmt">//--- Array of symbol inverse flags class="type">bool inverse[SYMBOLS_COUNT]; class=class="str">"cmt">//--- Colors of indicator lines class="type">color line_colors[SYMBOLS_COUNT]={clrDodgerBlue,clrLimeGreen,clrGold,clrAqua,clrMagenta}; class=class="str">"cmt">//--- String representing the lack of the symbol class="type">class="kw">string empty_symbol="EMPTY"; class=class="str">"cmt">//--- Chart properties class="type">int window_number =WRONG_VALUE; class=class="str">"cmt">// Indicator window number class="type">int chart_width =class="num">0; class=class="str">"cmt">// Chart width class="type">int chart_height =class="num">0; class=class="str">"cmt">// Chart height
把指标参数和画布底子先钉死
写自定义指标时,先把图表尺寸、中心坐标和配色这类全局变量在文件顶部一次性声明,后续重绘逻辑就不用反复算。下面这段就是某背离指标里实际用的初始化块,last_chart_width 和 last_chart_height 初始为 0,意味着首次 OnCalculate 必然要走一次尺寸重捕。 canvas_opacity 取 190(0~255 区间),黑底叠加在报价图上还留了约 25% 的透,不会完全挡掉裸 K。font_size 给 16、font_name 写死 Calibri,是为了在 1920 宽屏下标签不挤;你换 4K 屏时这个数可能要调到 22 才顺眼。 prefix 用指标短名加下划线拼出来,所有图形对象名都挂这个前缀,MT5 里删对象时一句 ObjectDelete 通配就干净,不会误伤别的 EA 画的线。 别把 clr_format 当摆设 COLOR_FORMAT_ARGB_RAW 要求你自己在颜色里排好 Alpha 通道顺序,用 clrBlack 这种宏没问题,但一旦手填 C'100,0,0' 就得确认顺序是 R-G-B 还是 B-G-R,填反了下跌柱线会渲染成怪色。开 MT5 把下面代码贴进 mq5 头部编译,看导航栏里 MS_PriceDivergence 前缀对象是否随加载自动建出来,就能验证这套命名有没有撞车。
class="type">int last_chart_width =class="num">0; class=class="str">"cmt">// Last saved chart width class="type">int last_chart_height =class="num">0; class=class="str">"cmt">// Last saved chart height class="type">int chart_center_x =class="num">0; class=class="str">"cmt">// Horizontal center of chart class="type">int chart_center_y =class="num">0; class=class="str">"cmt">// Vertical center of chart class="type">color color_bar_up =clrRed; class=class="str">"cmt">// Up bar class="type">color class="type">color color_bar_down =C&class="macro">#x27;class="num">100,class="num">0,class="num">0&class="macro">#x27;; class=class="str">"cmt">// Down bar class="type">color class="type">class="kw">string indicator_shortname ="MS_PriceDivergence"; class=class="str">"cmt">// Short name of the indicator class="type">class="kw">string prefix =indicator_shortname+"_"; class=class="str">"cmt">// Prefix for objects class=class="str">"cmt">//--- Name of vertical line of the price divergence starting point class="type">class="kw">string start_price_divergence=prefix+"start_price_divergence"; class=class="str">"cmt">//--- Canvas properties class="type">class="kw">string canvas_name =prefix+"canvas"; class=class="str">"cmt">// Canvas name class="type">color canvas_background =clrBlack; class=class="str">"cmt">// Canvas background class="type">color class="type">uchar canvas_opacity =class="num">190; class=class="str">"cmt">// Opacity class="type">int font_size =class="num">16; class=class="str">"cmt">// Font size class="type">class="kw">string font_name ="Calibri"; class=class="str">"cmt">// Font ENUM_COLOR_FORMAT clr_format =COLOR_FORMAT_ARGB_RAW; class=class="str">"cmt">// Color components should be correctly set by the user class=class="str">"cmt">//--- Canvas messages class="type">class="kw">string msg_prepare_data ="Preparing data! Please wait...";