手工图表和交易工具包(第一部分)。 准备:结构描述和助手类·进阶篇
「光标状态被收进一个静态类」
做 MT5 自定义指标或 EA 时,想实时拿到鼠标在图上的位置,最省事的办法是把光标参数集中到一个类里。这里有一套实现把 X/Y 像素坐标、对应柱线序号、光标处的时间与价格,以及光标相对当前柱高低的位置标记,全部存进 Mouse.mqh。 这个类的方法全声明为 static,意味着你不用 new 一个实例,直接在任意 .mq5 文件里写 CMouse::X() 就能取数。对价格行为交易者来说,这等于随时能知道「用户正悬停在哪根 K 线、哪个价位」,做悬停标注或交互式画线都够用。 外汇和贵金属波动快、杠杆高,这类交互只辅助看盘,不能单独作为下单依据,信号误读可能放大亏损。 下面这段是类的骨架,逐行看: //+------------------------------------------------------------------+
| // | Mouse.mqh |
|---|---|
| // | Copyright 2020, MetaQuotes Software Corp. |
| // | [MQL5官方文档] |
//+------------------------------------------------------------------+ // 文件头注释,标明出处与链接,仅作版权声明 #property copyright "Copyright 2020, MetaQuotes Software Corp." // 编译器属性:版权信息 #property link "[MQL5官方文档] // 编译器属性:相关文章链接 //+------------------------------------------------------------------+
| // | Mouse movement handling class |
|---|
//+------------------------------------------------------------------+ class CMouse // 定义鼠标处理类 CMouse { //--- Members private: // 私有成员区 static int m_x; // X // 静态整型:光标 X 像素坐标 static int m_y; // Y // 静态整型:光标 Y 像素坐标 static int m_barNumber; // Bar number // 静态整型:光标所在柱线序号 static bool m_below; // Indication of a cursor above the price // 静态布尔:标记光标是否在价格下方 static bool m_above; // Indication of a cursor below the price // 静态布尔:标记光标是否在价格上方 static datetime m_currentTime; // Current time // 静态时间:光标处对应的 K 线时间 static double m_currentPrice;// Current price // 静态双精度:光标处对应的价格 //--- Methods public: // 公有方法区 //--- Remembers the main parameters of the mouse cursor static void SetCurrentParameters( // 静态方法:把鼠标事件参数写进上述静态成员 const int id, // 事件 ID const long &lparam, // 长整型参数(通常含坐标) const double &dparam, // 双精度参数 const string &sparam // 字符串参数 ); //--- Returns the X coordinate (in pixels) of the current cursor position static int X(void) {return m_x;} // 取光标 X 像素坐标 //--- Returns the Y coordinate (in pixels) of the current cursor position static int Y(void) {return m_y;} // 取光标 Y 像素坐标 //--- Returns the price of the current cursor position static double Price(void) {return m_currentPrice;} // 取光标处价格 //--- Returns the time of the current cursor position static datetime Time(void) {return m_currentTime;} // 取光标处时间 //--- Returns the bar number of the current cursor position static int Bar(void) {return m_barNumber;} // 取光标处柱线序号 //--- Returns a flag showing that the price is below the Low of the current bar // 后续还有判断光标与柱体低/高关系的标志方法(此处截断)
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Mouse.mqh | class=class="str">"cmt">//| Copyright class="num">2020, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2020, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Mouse movement handling class | class=class="str">"cmt">//+------------------------------------------------------------------+ class CMouse { class=class="str">"cmt">//--- Members class="kw">private: class="kw">static class="type">int m_x; class=class="str">"cmt">// X class="kw">static class="type">int m_y; class=class="str">"cmt">// Y class="kw">static class="type">int m_barNumber; class=class="str">"cmt">// Bar number class="kw">static class="type">bool m_below; class=class="str">"cmt">// Indication of a cursor above the price class="kw">static class="type">bool m_above; class=class="str">"cmt">// Indication of a cursor below the price class="kw">static class="type">class="kw">datetime m_currentTime; class=class="str">"cmt">// Current time class="kw">static class="type">class="kw">double m_currentPrice;class=class="str">"cmt">// Current price class=class="str">"cmt">//--- Methods class="kw">public: class=class="str">"cmt">//--- Remembers the main parameters of the mouse cursor class="kw">static class="type">void SetCurrentParameters( class="kw">const class="type">int id, class="kw">const class="type">long &lparam, class="kw">const class="type">class="kw">double &dparam, class="kw">const class="type">class="kw">string &sparam ); class=class="str">"cmt">//--- Returns the X coordinate(in pixels) of the current cursor position class="kw">static class="type">int X(class="type">void) {class="kw">return m_x;} class=class="str">"cmt">//--- Returns the Y coordinate(in pixels) of the current cursor position class="kw">static class="type">int Y(class="type">void) {class="kw">return m_y;} class=class="str">"cmt">//--- Returns the price of the current cursor position class="kw">static class="type">class="kw">double Price(class="type">void) {class="kw">return m_currentPrice;} class=class="str">"cmt">//--- Returns the time of the current cursor position class="kw">static class="type">class="kw">datetime Time(class="type">void) {class="kw">return m_currentTime;} class=class="str">"cmt">//--- Returns the bar number of the current cursor position class="kw">static class="type">int Bar(class="type">void) {class="kw">return m_barNumber;} class=class="str">"cmt">//--- Returns a flag showing that the price is below the Low of the current bar
◍ 鼠标坐标到价格时间的静态映射
CMouse 类用一组 static 成员变量缓存鼠标状态:m_x、m_y 存像素坐标,m_currentTime 与 m_currentPrice 存由坐标反推的图表时间价格,m_below / m_above 标记光标相对当前 K 线高低点的位置。类外初始化里这些变量全部置零或 false,意味着指标加载后、首次鼠标移动事件前,读到的都是默认值。 SetCurrentParameters 是核心:它接收 Windows 消息的 lparam(X 像素)和 dparam(Y 像素),调用 ChartXYToTimePrice 把像素转成时间价格,写回 m_currentTime / m_currentPrice,同时把原始像素存进 m_x / m_y。 随后用 iBarShift 按 m_currentTime 找到对应 K 线序号 m_barNumber,再用 iLow / iHigh 比较光标价格与这根 K 线的最低最高价,得出 m_below 与 m_above。外汇与贵金属市场跳空频繁,这种比较只基于当前周期 PERIOD_CURRENT 的单根 K 线,跨周期或跳空缺口下 m_above/m_below 可能偏离视觉预期,开 MT5 挂个鼠标事件打印这几个值就能验证。
class="kw">static class="type">bool Below(class="type">void) {class="kw">return m_below;} class=class="str">"cmt">//--- Returns a flag showing that the price is above the High of the current bar class="kw">static class="type">bool Above(class="type">void) {class="kw">return m_above;} }; class=class="str">"cmt">//--- class="type">int CMouse::m_x=class="num">0; class="type">int CMouse::m_y=class="num">0; class="type">int CMouse::m_barNumber=class="num">0; class="type">bool CMouse::m_below=class="kw">false; class="type">bool CMouse::m_above=class="kw">false; class="type">class="kw">datetime CMouse::m_currentTime=class="num">0; class="type">class="kw">double CMouse::m_currentPrice=class="num">0; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Remembers the main parameters for a mouse movement: coordinates | class=class="str">"cmt">//| of cursor in pixels and price/time, whether the cursor is | class=class="str">"cmt">//| above or below the price. | class=class="str">"cmt">//|+-----------------------------------------------------------------+ class="kw">static class="type">void CMouse::SetCurrentParameters( class="kw">const class="type">int id, class="kw">const class="type">long &lparam, class="kw">const class="type">class="kw">double &dparam, class="kw">const class="type">class="kw">string &sparam ) { class=class="str">"cmt">//--- class="type">int window = class="num">0; class=class="str">"cmt">//--- ChartXYToTimePrice( class="num">0, (class="type">int)lparam, (class="type">int)dparam, window, m_currentTime, m_currentPrice ); m_x=(class="type">int)lparam; m_y=(class="type">int)dparam; m_barNumber=iBarShift( Symbol(), PERIOD_CURRENT, m_currentTime ); m_below=m_currentPrice<iLow(Symbol(),PERIOD_CURRENT,m_barNumber); m_above=m_currentPrice>iHigh(Symbol(),PERIOD_CURRENT,m_barNumber); }
用户参数全塞在 GlobalVariables 里
这套 MT5 工具的对外可调项,目前统一收口在 GlobalVariables.mqh 这一个头文件里,没有散落到各 EA 或指标主体中。后续篇章会随图形对象增多继续补设置项,但结构不会变:所有 input 常量都在此集中声明。 当前版本已经暴露了两组关键映射:键盘热键与画线参数。比如周期切换绑定 U(升周期)和 D(降周期),趋势线用 T 拉、射线模式用 R 切、置顶图表用 Z;画线宽度写死为 2,线型默认 STYLE_SOLID。 直接在 MT5 的 MetaEditor 里打开该文件改键值就能重绑操作习惯,不用碰主逻辑。外汇与贵金属品种波动剧烈、杠杆风险高,热键误触可能瞬间下错单,建议先在模拟盘验证映射。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| GlobalVariables.mqh | class=class="str">"cmt">//| Copyright class="num">2020, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2020, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| File describing parameters available to the user | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Key settings | class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">input class="type">class="kw">string Keys="=== Key settings ==="; class="kw">input class="type">class="kw">string Up_Key="U"; class=class="str">"cmt">// Switch timeframe up class="kw">input class="type">class="kw">string Down_Key="D"; class=class="str">"cmt">// Switch timeframe down class="kw">input class="type">class="kw">string Trend_Line_Key="T"; class=class="str">"cmt">// Trend line class="kw">input class="type">class="kw">string Switch_Trend_Ray_Key="R"; class=class="str">"cmt">// Indication of a trend line ray class="kw">input class="type">class="kw">string Z_Index_Key="Z"; class=class="str">"cmt">// Indication of the chart on top class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Size settings | class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">input class="type">class="kw">string Dimensions="=== Size settings ==="; class="kw">input class="type">int Trend_Line_Width=class="num">2; class=class="str">"cmt">// Trend line width class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Display styles | class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">input class="type">class="kw">string Styles="=== Display styles ==="; class="kw">input ENUM_LINE_STYLE Trend_Line_Style=STYLE_SOLID; class=class="str">"cmt">// Trend line style class=class="str">"cmt">//+------------------------------------------------------------------+
「辅助参数与隐藏前缀的取舍」
这段配置决定了 EA 在画趋势线时的「脾气」:是否射线延伸、跨周期显隐、创建即选中,以及左右分形臂长。Is_Trend_Ray 默认 false,代表趋势线以线段收口而非无限射线;若做日内突破跟踪,改成 true 可能更贴合视觉。 Is_Change_Timeframe_On_Create 默认 true,意即较高周期上自动隐藏本周期对象,避免图表被低周期线糊满;Is_Select_On_Create 与 Is_Different_Colors 同为 true,创建时自动选中且按周期换色,方便立刻拖拽微调。 Fractal_Size_Left / Right 都是 1,说明极值判定只看相邻 1 根 K 线,属于最紧的刺透判定;遇到滑点大的贵金属品种,可能需调到 2~3 才不易被毛刺误触。外汇与贵金属杠杆高,参数改动前建议先开 MT5 策略测试器用历史数据验证。 前缀与配色写死在代码里不进输入项:Trend_Line_Prefix 为 "Trend_",周期色从 mn1 的 Crimson 到 m1 的 DarkViolet 共 10 档。想统一改色直接动代码里的 color 常量即可,不用碰 EA 面板。
class=class="str">"cmt">//| Other parameters class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">input class="type">class="kw">string Others="=== Other parameters ==="; class="kw">input class="type">bool Is_Trend_Ray=class="kw">false; class=class="str">"cmt">// Trend line - ray class="kw">input class="type">bool Is_Change_Timeframe_On_Create = true; class=class="str">"cmt">// Hide objects on higher timeframes? class=class="str">"cmt">// (true - hide, class="kw">false - show) class="kw">input class="type">bool Is_Select_On_Create=true; class=class="str">"cmt">// Select upon creation class="kw">input class="type">bool Is_Different_Colors=true; class=class="str">"cmt">// Change colors for times class=class="str">"cmt">// Number of bars on the left and on the right class=class="str">"cmt">// for trend line and fan extreme points class="kw">input class="type">int Fractal_Size_Left=class="num">1; class=class="str">"cmt">// Size of the left fractal class="kw">input class="type">int Fractal_Size_Right=class="num">1; class=class="str">"cmt">// Size of the right fractal class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Name prefixes of drawn shapes(can be change only in code, | class=class="str">"cmt">//| not visible in EA parameters) | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">// class="type">class="kw">string Prefixes="=== Prefixes ==="; class="type">class="kw">string Trend_Line_Prefix="Trend_"; class=class="str">"cmt">// Trend line prefix class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Colors for objects of one timeframe(can be changed only in code,| class=class="str">"cmt">//| not visible in EA parameters) | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">// class="type">class="kw">string TimeframeColors="=== Time frame colors ==="; class="type">color mn1_color=clrCrimson; class="type">color w1_color=clrDarkOrange; class="type">color d1_color=clrGoldenrod; class="type">color h4_color=clrLimeGreen; class="type">color h1_color=clrLime; class="type">color m30_color=clrDeepSkyBlue; class="type">color m15_color=clrBlue; class="type">color m5_color=clrViolet; class="type">color m1_color=clrDarkViolet; class="type">color common_color=clrGray; class=class="str">"cmt">//--- Auxiliary constant for displaying error messages class="macro">#define DEBUG_MESSAGE_PREFIX "=== ",__FUNCTION__," === " class=class="str">"cmt">//--- Constants for describing the main timeframes when drawing
◍ 用位掩码拼出周期包含关系
在 MT5 里给图表对象设定时间周期可见性时,逐个写周期常量既啰嗦又难维护。把 OBJ_PERIOD_* 系列常量做按位或,就能用一条宏表达「某周期及其以下所有小周期」的可见集合。 上面这段预处理定义从 M1 起步,逐级把更小周期用位或叠进去:PERIOD_LOWER_M5 实际等于 M1|M5 的位掩码,PERIOD_LOWER_H1 则覆盖了 M1 到 H1 共 6 个周期位。这样在创建对象时传 PERIOD_LOWER_H1,对象便只会在 H1 及更短周期图表上显示。 外汇与贵金属杠杆品种波动剧烈,用这类宏控制对象显示范围时,仍要在多周期回测里确认对象不会被误隐藏,高风险环境下显示逻辑错漏可能直接干扰信号判断。
class="macro">#define PERIOD_LOWER_M5 OBJ_PERIOD_M1|OBJ_PERIOD_M5 class="macro">#define PERIOD_LOWER_M15 PERIOD_LOWER_M5|OBJ_PERIOD_M15 class="macro">#define PERIOD_LOWER_M30 PERIOD_LOWER_M15|OBJ_PERIOD_M30 class="macro">#define PERIOD_LOWER_H1 PERIOD_LOWER_M30|OBJ_PERIOD_H1 class="macro">#define PERIOD_LOWER_H4 PERIOD_LOWER_H1|OBJ_PERIOD_H4 class="macro">#define PERIOD_LOWER_D1 PERIOD_LOWER_H4|OBJ_PERIOD_D1 class="macro">#define PERIOD_LOWER_W1 PERIOD_LOWER_D1|OBJ_PERIOD_W1 class=class="str">"cmt">//+------------------------------------------------------------------+
支撑绘图的非绘图工具函数
在 MT5 里写交互式画线脚本,真正麻烦的往往不是 ObjectCreate 本身,而是周期切换、极值定位、唯一命名这些杂活。这些逻辑通常塞进一个 Utilities.mqh 之类的头文件,和绘图代码解耦,方便在不同 EA/脚本间复用。 顺序切周期是最常被调用的小函数:先在建好的时间帧数组里用 Period() 抓当前周期,定位下标后把下一个元素丢给 ChartSetSymbolPeriod。注意数组若写死 MT5 全部周期常量,在 MQL4 环境会丢失兼容性,跨平台项目别这么干。 找极值靠 GetNearestExtremumBarNumber,参数能控制向左还是向右搜、极值左右各比几根 Bar。画趋势线时一般取鼠标右侧最近两个极值,套这个函数就能拿到 Bar 序号。对象命名则建议用类型前缀加自增数字,GlobalVariables.mqh 里能查前缀表;编号搜索有两条路,主算法扫同前缀对象填“空隙”,另一算法按总数递增避让不同后缀,草叉集合那种多后缀场景得用第二条。 算像素距离时,最稳的是先测相邻两根 Bar 的像素差再乘系数,比直接读窗口坐标抗缩放。斐波那契级别若想用逗号字符串在 EA 参数里配,就用字符串转 double 数组的函数喂给 MQL 接口。外汇和贵金属波动大、杠杆高,这类辅助函数只解决坐标与命名,不构成任何方向判断。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Utilites.mqh | class=class="str">"cmt">//| Copyright class="num">2020, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2020, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class describing auxiliary functions | class=class="str">"cmt">//+------------------------------------------------------------------+ class CUtilites { class="kw">public: class=class="str">"cmt">//--- Changes the timeframe to the next one on the toolbar class="kw">static class="type">void ChangeTimeframes(class="type">bool isUp); class=class="str">"cmt">//--- Converts class="type">class="kw">string command constants to keycodes class="kw">static class="type">int GetCurrentOperationChar(class="type">class="kw">string keyString); class=class="str">"cmt">//--- Switches layers in charts(the chart is on top of all objects) class="kw">static class="type">void ChangeChartZIndex(class="type">void); class=class="str">"cmt">//--- Returns the number of the nearest extreme bar class="kw">static class="type">int GetNearestExtremumBarNumber( class="type">int starting_number=class="num">0, class="type">bool is_search_right=class="kw">false, class="type">bool is_up=class="kw">false, class="type">int left_side_bars=class="num">1, class="type">int right_side_bars=class="num">1, class="type">class="kw">string symbol=NULL, ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT ); class=class="str">"cmt">//--- Returns the class="type">color for the current timeframe class="kw">static class="type">color GetTimeFrameColor(class="type">long allDownPeriodsValue); class=class="str">"cmt">//--- Returns a list of all timeframes lower than the current one(including the current one) class="kw">static class="type">long GetAllLowerTimeframes(class="type">int NeededTimeframe=PERIOD_CURRENT); class=class="str">"cmt">//--- Coordinates of the straight line. Writes numbers of extreme bars to points p1 and p2 class="kw">static class="type">void SetExtremumsBarsNumbers(class="type">bool _is_up,class="type">int &p1, class="type">int &p2);