DoEasy.服务功能(第 2 部分):孕线形态·综合运用
(3/3)·把母柱与界定柱的时间差变成可绘制框架,顺带给后续形态类型留好扩展口
不少自行实现的 Inside Bar 检测器只比对单根比例,遇到连续嵌套的孕线就漏判或重复标记。母柱与界定柱的开启时间差若不被记录,图表上根本分不清一组嵌套到底吞了几根 K 线。
- 多语言报错与图形对象属性表的写法
- 参数兜底与形态命名的底层函数
- 把形态枚举塞进 ulong 位标记
- 把形态位域翻译成可读文本
- 控件对象的内部属性字段拆解
- 图形对象的文本坐标存取细节
- 给图表挂上可绘制的位图对象
- 位图元素的类骨架与坐标锚定
- 位图对象的构造参数与默认初始化
- 图形对象的时空锚点与析构清理
- 图形元素构造时的背景与坐标初始化
- 位图容器构造时的参数与默认态
- 在MT5里用代码画出可定位的位图画布
- 给位图对象钉死时间和价格锚点
- 在图表上挂自定义位图对象的底层入口
- 窗体与主图位图的多重载创建入口
- K线类里怎么挂形态标记
- CBar 类怎么把一根 K 线变成可查询对象
- 把单根 K 线的维度写进属性表
- K线属性描述的嵌套三元拼装
- K线时间字段与形态类型的字符串拼装
- 形态类里的属性索引与私有成员
- 形态类的内部字段与属性读写
- 形态对象的存取与属性接口
- 图形对象的属性读取接口
- 形态类里取价与挂母柱的接口
- 母柱属性的存取接口
- 形态对象的属性描述与绘图接口
- 图形对象生命周期与配色接口
- 图形对象的显示与图表参数接口
- 形态对象的初始化与析构逻辑
- 形态对象怎么把属性翻成可读文本
- 母柱数据注入与信息面板防越界
- 形态图标在图表上的显隐与尺寸换算
- Pin Bar 识别类的构造落点
- 孕线形态的控制类怎么落地
- Inside Bar 类的属性与面板构造细节
- Inside Bar 面板的自适应绘制逻辑
- 内包线图案的图表绘制逻辑
- 形态控件的底层成员与绘制开关
- 图形搜索类的成员与虚函数骨架
- 把 K 线对象塞进 MqlRates 的底层写法
- 蜡烛比例与绘制开关的存取接口
- K线对象的状态读取与图表参数注入
- 图表边界与形态控制类的存取接口
- 形态控制器的初始化与扫描入口
- 母柱数据怎么挂到新形态对象上
- Pin Bar 控制类如何切换点状绘制与生成唯一码
- Pin Bar 控制类的构造与实例化落点
- Pin Bar 识别的实体与影线比例门槛
- Inside Bar 的母子棒判定逻辑
- 内包线识别里的母柱赋值与跳出逻辑
- 内包线判定的代码骨架
- 内包线母柱的循环判定与对象生成
- Inside Bar 控制类的判定与取链逻辑
- 内包线控件的检索与按需创建
- 把形态对象挂进列表并清零比例参数
- 用点状标记切换 K 线形态绘制
- 把星线与十字星切换成点状绘制
- 把形态标记切换成点阵的接口细节
- Pin Bar 点状绘制与参数阈值
- 蜡烛图形态的点状绘制开关
- 蜡烛图点状绘制标记的读取接口
- 星线与墓碑十字的虚线绘制开关
- 价格行为形态的点状绘制开关
- 用点阵标记切换形态画法
- 用点阵标记切换 K 线形态绘制
- 用点状标记切换 K 线形态显示
- 把吊人线与十字星改成点状绘制
- 用点状标记切换星线形态显示
- 用点阵切换 K 线形态绘制
- Pin Bar 点阵绘制的阈值入口
- 形态点状绘制的开关判定
- 用点状标记切换蜡烛图形态显示
- 星线族的点状绘制开关怎么查
- 点阵形态绘制的布尔开关怎么写
- 用点阵标记形态时的判定与开关
- 按形态逐个开关点阵绘制
- 把价格行为形态画成点阵的开关函数
- 按周期开关 K 线形态的点状绘制
- 用点状标记切换 K 线形态识别
- 按周期切换 K 线形态的点状标记
- 按时间框架逐个点亮 K 线形态圆点
- 用点阵切换价格行为形态显隐
- 用点阵切换形态绘制的开关与回读
- 按周期取蜡烛图形态的点状绘制开关
- 按周期取价格行为形态的虚线绘制开关
- 多品种K线形态的集合类怎么管
- 逐个形态开关的点阵绘制函数
- 把星线与孕线转成点阵标记的函数接口
- Pin Bar 与 Rails 的虚线绘制开关
- 逐形态查询点状绘制开关
- 点状标记里藏着的形态开关
- 用点阵标记切换 K 线形态显示
- 把形态标成点位的开关函数
- 按品种分时切换 K 线形态的点状标记
- 用点状标记切换星线与Pivot反转的绘制
- 用点阵标记三类价格行为形态
- 用点状标记切换 K 线形态绘制
- 用点状标记切换 K 线形态显隐
- 蜡烛图点阵绘制标记的批量透传
- 点阵标记各形态开关的集中实现
- 用点阵标记把反转形态搬上图表
- 用点状标记切换 K 线形态显示
- 用点状标记切换 K 线形态显示
- 用点状标记切换 K 线形态显隐
- 把反转形态画成点阵而非连线
- 用点阵标记价格行为形态的代码入口
- K线形态绘制接口的隐藏开关
- 按K线时间收起多余形态面板
- 给交易对象加 spread 倍数并抓市场观察事件
- 把形态检测 EA 跑起来验证
- EA 输入参数里藏着的多品种 Pin Bar 扫描逻辑
- 在鼠标移动里反算K线坐标
- 把光标所在K线的形态逐个挂上信息面板
- 空代码块的截断现场
- 下一篇接着拆时间序列形态
多语言报错与图形对象属性表的写法
在 MT5 里做跨语言提示和图形对象封装时,常把错误码和界面文案塞进二维数组。下面这段用 messages_library[][TOTAL_LANG] 存了俄英双语,TOTAL_LANG 一般等于 2,索引 0 是俄文、1 是英文,终端按当前语言取列。 有几个版本门槛值得记:数组里明确写了 MetaTrader5 build 低于 2155、3245、3260 时某些属性不被支持。你在本机按 F1 看终端版本号,若低于 3260,调用对应属性会直接走“not supported”分支,不是代码写错。 图形元素相关的字符串属性也在这里统一定义,比如“Image resource name”“Text of the graphic element”“Element tooltip header”。做蜡烛形态标注时,还会碰到 Bitmap 对象设置时间与价格的失败提示:Failed to set time value to Bitmap object / Failed to set price value to Bitmap object,对应前面 MSG_ERR_FAILED_SET_BITMAP_OBJ_TIME 和 MSG_ERR_FAILED_SET_BITMAP_OBJ_PRICE 两个错误常量。 外汇与贵金属图表上加自定义 Bitmap 属高风险操作环境,版本不匹配可能导致对象不显示或脚本静默失败,建议先在策略测试器用 EURUSD 1 分钟历史数据验证。
MSG_ERR_FAILED_SET_BITMAP_OBJ_TIME, class=class="str">"cmt">// Failed to set the time value to the Bitmap object MSG_ERR_FAILED_SET_BITMAP_OBJ_PRICE, class=class="str">"cmt">// Failed to set the price value for the Bitmap object }; class="type">class="kw">string messages_library[][TOTAL_LANG]= { {"Начало списка параметров","The beginning of the parameter list"}, {"Конец списка параметров","End of parameter list"}, {"Свойство не поддерживается","Property not supported"}, {"Свойство не поддерживается в MQL4","Property not supported in MQL4"}, {"Свойство не поддерживается в MetaTrader5 версии ниже class="num">2155","The class="kw">property is not supported in MetaTrader5, build lower than class="num">2155"}, {"Свойство не поддерживается в MetaTrader5 версии ниже class="num">3245","The class="kw">property is not supported in MetaTrader5, build lower than class="num">3245"}, {"Свойство не поддерживается в MetaTrader5 версии ниже class="num">3260","The class="kw">property is not supported in MetaTrader5, build lower than class="num">3260"}, {"Свойство не поддерживается у позиции","Property not supported for position"}, {"Свойство не поддерживается у отложенного ордера","The class="kw">property is not supported for a pending order"}, {"Свойство не поддерживается у маркет-ордера","The class="kw">property is not supported for a market-order"}, {"Свойство не поддерживается у исторического маркет-ордера","The class="kw">property is not supported for a history market-order"}, {"Значение не задано","Value not set"}, {"Отсутствует","Not set"}, {"Не найдено","Not found"}, {"Формируется терминалом","Formed by the terminal"}, {"В соответствии с режимом истечения ордера","In accordance with the order expiration mode"}, {"Отношение тела свечи к полному размеру свечи","Ratio of candle body to full candle size"}, {"Отношение размера верхней тени к размеру свечи","Ratio of the upper shadow size to the candle size"}, {"Отношение размера нижней тени к размеру свечи","Ratio of the lower shadow size to the candle size"}, {"Типы паттернов на баре","Types of patterns on the bar"}, class=class="str">"cmt">//--- CTimeSeries class=class="str">"cmt">//--- CPattern {"Код","Code"}, {"Время определяющего бара","Time of the defining bar"}, {"Время \"материнского\" бара","Time open of the mother bar"}, {"Идентификатор паттерна","Pattern ID"}, {"Идентификатор объекта управления паттерном","Pattern Control object ID"}, {"Расширенный стандартный графический объект","Extended standard graphic object"}, {"Элемент","Element"}, {"Рисунок","Bitmap"}, {"Объект тени","Shadow object"}, {"Форма","Form"}, class=class="str">"cmt">//--- String properties of graphical elements {"Имя объекта-графического элемента","The name of the graphic element object"}, {"Имя графического ресурса","Image resource name"}, {"Текст графического элемента","Text of the graphic element"}, {"Описание графического элемента","Description of the graphic element"}, {"Заголовок подсказки элемента","Element tooltip header"}, {"Текст подсказки элемента","Element tooltip title"}, class=class="str">"cmt">//--- CGCnvBitmap {"Не удалось установить значение времени Bitmap-объекту","Failed to set time value to Bitmap object"}, {"Не удалось установить значение цены Bitmap-объекту","Failed to set price value to Bitmap object"}, };
「参数兜底与形态命名的底层函数」
在写价格行为扫描器时,符号和时间帧如果传空或传 PERIOD_CURRENT,直接拿去调 iBar 系列函数会返回不可预期结果。下面两个小函数把输入先归一化:符号为空串或 NULL 时回退到当前图表 Symbol(),时间帧为 PERIOD_CURRENT 时回退到 Period(),这样上层逻辑不用到处写判断。 形态类型到可读文本的映射靠一个 switch 覆盖 14 种 K 线形态,包括 HARAMI、TWEEZER、PIERCING_LINE、DARK_CLOUD_COVER、三白兵、三乌鸦,以及 DOJI 家族的三种变体。注意这里返回的是 CMessage::Text(...) 的本地化字符串,不是硬编码英文,意味着你换终端语言环境,小布弹窗里显示的形态名会自动跟着变。 开 MT5 把这段直接塞进你的 EA 头文件,调用 CorrectSymbol("") 应得到当前品种名;把 PERIOD_CURRENT 喂给 CorrectTimeframe 应拿到如 5 或 15 的实际周期枚举。外汇和贵金属杠杆高,形态识别只提示概率倾向,别拿它当入场唯一依据。
class="type">class="kw">string CorrectSymbol(class="kw">const class="type">class="kw">string symbol) { class="kw">return(symbol==NULL || symbol=="" ? ::Symbol() : symbol); } ENUM_TIMEFRAMES CorrectTimeframe(class="kw">const ENUM_TIMEFRAMES timeframe) { class="kw">return(timeframe==PERIOD_CURRENT ? ::Period() : timeframe); } class="type">class="kw">string PatternTypeDescription(class="kw">const ENUM_PATTERN_TYPE type) { class="kw">switch(type) { case PATTERN_TYPE_HARAMI : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HARAMI); case PATTERN_TYPE_HARAMI_CROSS : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HARAMI_CROSS); case PATTERN_TYPE_TWEEZER : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_TWEEZER); case PATTERN_TYPE_PIERCING_LINE : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_PIERCING_LINE); case PATTERN_TYPE_DARK_CLOUD_COVER : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_DARK_CLOUD_COVER); case PATTERN_TYPE_THREE_WHITE_SOLDIERS : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_THREE_WHITE_SOLDIERS); case PATTERN_TYPE_THREE_BLACK_CROWS : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_THREE_BLACK_CROWS); case PATTERN_TYPE_SHOOTING_STAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_SHOOTING_STAR); case PATTERN_TYPE_HAMMER : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HAMMER); case PATTERN_TYPE_INVERTED_HAMMER : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_INVERTED_HAMMER); case PATTERN_TYPE_HANGING_MAN : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HANGING_MAN); case PATTERN_TYPE_DOJI : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_DOJI); case PATTERN_TYPE_DRAGONFLY_DOJI : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_DRAGONFLY_DOJI); case PATTERN_TYPE_GRAVESTONE_DOJI : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_GRAVESTONE_DOJI); } }
◍ 把形态枚举塞进 ulong 位标记
这段逻辑干了两件事:先用 switch 把 12 种蜡烛形态枚举映射成可读文本,再用位运算把多个形态压进一个 ulong 变量。PATTERN_TYPE_MORNING_STAR 到 PATTERN_TYPE_RAILS 逐个 case 返回对应消息宏,default 回落到 MSG_LIB_TEXT_FRAME_STYLE_NONE,说明未识别时不当成任何形态。 ListPatternsInVar 才是重点。循环从 i=1 跑到 PATTERNS_TOTAL-1,每次把 x 按 2 的幂递增(i>1 时 x=x*2),用 (var & type)==type 检测该位是否被置起。命中就 size++ 并 ArrayResize 写入 array,最终返回命中的形态数量。 你在 MT5 里若想一次查某 K 线组合包含哪几种形态,直接传一个按位或好的 ulong 进这个函数,array 里拿到的就是具体枚举值。外汇和贵金属波动快,形态误判概率不低,这类位标记只解决“存和取”,不解决“准不准”。
case PATTERN_TYPE_MORNING_STAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_MORNING_STAR); case PATTERN_TYPE_MORNING_DOJI_STAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_MORNING_DOJI_STAR); case PATTERN_TYPE_EVENING_STAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_EVENING_STAR); case PATTERN_TYPE_EVENING_DOJI_STAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_EVENING_DOJI_STAR); case PATTERN_TYPE_THREE_STARS : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_THREE_STARS); case PATTERN_TYPE_ABANDONED_BABY : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_ABANDONED_BABY); case PATTERN_TYPE_PIVOT_POINT_REVERSAL: class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_PIVOT_POINT_REVERSAL); case PATTERN_TYPE_OUTSIDE_BAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_OUTSIDE_BAR); case PATTERN_TYPE_INSIDE_BAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_INSIDE_BAR); case PATTERN_TYPE_PIN_BAR : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_PIN_BAR); case PATTERN_TYPE_RAILS : class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_RAILS); case PATTERN_TYPE_DEFAULT : class="kw">return CMessage::Text(MSG_LIB_TEXT_FRAME_STYLE_NONE); } } class="type">int ListPatternsInVar(class="kw">const class="type">ulong var,class="type">ulong &array[]) { class="type">int size=class="num">0; class="type">ulong x=class="num">1; for(class="type">int i=class="num">1;i<PATTERNS_TOTAL;i++) { x=(i>class="num">1 ? x*class="num">2 : class="num">1); ENUM_PATTERN_TYPE type=(ENUM_PATTERN_TYPE)x; class="type">bool res=(var & type)==type; if(res) { size++; ArrayResize(array,size,PATTERNS_TOTAL-class="num">1); array[size-class="num">1]=type; } } class="kw">return size; }
把形态位域翻译成可读文本
在 MT5 里把多个蜡烛形态压进一个 ulong 位域后,肉眼无法直接读出其中包含了哪些形态。下面两个函数就是把位域还原成文字说明的实用工具,一个直接 Print 到日志,一个返回字符串供界面调用。 PatternsInVarDescriptionPrint 接收 ulong 变量 var 和可选 dash 参数。内部先调用 ListPatternsInVar 把命中的形态枚举塞进 array,返回数量 total;随后用 for 循环遍历,把每个枚举转成 PatternTypeDescription 文本,dash 为 true 时行首补「 - 」再 Print。 PatternsInVarDescription 逻辑类似,但把每行描述拼进 txt 字符串,除最后一项外用 "\n" 换行,最终 return 整段文本。实盘里若同时识别了 3 种形态,total 就等于 3,日志会逐行列出,方便你接小布盯盘做告警。 紧随其后的 CGCnvElement 类继承自 CGBaseObj,封装了画布、暂停、阴影开关与背景色数组,是后续把形态画到图表上的图形元素基类。外汇与贵金属波动剧烈,这类可视化仅作辅助,信号失效概率始终存在。
class="type">void PatternsInVarDescriptionPrint(class="kw">const class="type">ulong var,class="kw">const class="type">bool dash=false) { class="type">ulong array[]; class=class="str">"cmt">//--- Get the number of patterns in the value passed to the function class="type">int total=ListPatternsInVar(var,array); class=class="str">"cmt">//--- In the loop by the array of patterns, obtain a description of the next pattern and print it for(class="type">int i=class="num">0;i<total;i++) Print((dash ? " - " : ""),PatternTypeDescription((ENUM_PATTERN_TYPE)array[i])); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return a description of pattern types in a class="type">ulong variable | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string PatternsInVarDescription(class="kw">const class="type">ulong var,class="kw">const class="type">bool dash=false) { class="type">ulong array[]; class=class="str">"cmt">//--- Get the number of patterns in the value passed to the function class="type">int total=ListPatternsInVar(var,array); class="type">class="kw">string txt=""; class=class="str">"cmt">//--- In the loop by the array of patterns, obtain a description of the next pattern and add it to the text variable for(class="type">int i=class="num">0;i<total;i++) txt+=((dash ? " - " : "")+PatternTypeDescription((ENUM_PATTERN_TYPE)array[i]))+(i<total-class="num">1 ? "\n" : ""); class=class="str">"cmt">//--- Return the obtained text class="kw">return txt; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class of the graphical element object | class=class="str">"cmt">//+------------------------------------------------------------------+ class CGCnvElement : class="kw">public CGBaseObj { class="kw">protected: CGCnvElement *m_element_main; class=class="str">"cmt">// Pointer to the initial parent element within all the groups of bound objects CGCnvElement *m_element_base; class=class="str">"cmt">// Pointer to the parent element within related objects of the current group CCanvas m_canvas; class=class="str">"cmt">// CCanvas class object CPause m_pause; class=class="str">"cmt">// Pause class object class="type">bool m_shadow; class=class="str">"cmt">// Shadow presence class="type">class="kw">color m_chart_color_bg; class=class="str">"cmt">// Chart background class="type">class="kw">color class="type">uint m_duplicate_res[]; class=class="str">"cmt">// Array for storing resource data copy class="type">class="kw">color m_array_colors_bg[]; class=class="str">"cmt">// Array of element background colors
「控件对象的内部属性字段拆解」
在 MT5 的 Canvas 图形库里,一个可交互控件(按钮、标签等)的背后是一组结构化成员变量,理解它们才能自己改 UI 逻辑。 下面这段声明涵盖了背景色状态、渐变开关、相对坐标偏移,以及从结构创建对象用的三类属性数组。 color m_array_colors_bg_dwn[]; // 鼠标按下时控件背景色数组 color m_array_colors_bg_ovr[]; // 鼠标悬停时控件背景色数组 bool m_gradient_v; // 是否启用垂直渐变填充 bool m_gradient_c; // 是否启用循环渐变填充 int m_init_relative_x; // 初始相对 X 坐标 int m_init_relative_y; // 初始相对 Y 坐标 color m_array_colors_bg_init[]; // 元素初始背景色数组 int m_shift_coord_x; // 相对基准对象的 X 坐标偏移 int m_shift_coord_y; // 相对基准对象的 Y 坐标偏移 创建对象分两步:先用结构描述,再从结构实例化。对应的属性容器是定长数组,容量由枚举总数决定: long m_long_prop[CANV_ELEMENT_PROP_INTEGER_TOTAL]; // 整型属性 double m_double_prop[CANV_ELEMENT_PROP_DOUBLE_TOTAL]; // 浮点属性 string m_string_prop[CANV_ELEMENT_PROP_STRING_TOTAL]; // 字符串属性 文本绘制相关还有锚点枚举与最近一次坐标缓存: ENUM_FRAME_ANCHOR m_text_anchor; // 当前文本对齐方式 int m_text_x; // 文本上次 X 坐标 int m_text_y; // 文本上次 Y 坐标 protected 下的 Initialize() 负责按元素类型、ID、序号填入默认值,你在派生类里重载前应先读一遍原构造,避免覆盖了坐标偏移逻辑。外汇与贵金属图表加载这类自定义控件存在刷新开销,高频 tick 下可能掉帧,建议先在回测可视化里验证。
class="type">class="kw">color m_array_colors_bg_dwn[]; class=class="str">"cmt">// Array of control background colors when clicking on the control class="type">class="kw">color m_array_colors_bg_ovr[]; class=class="str">"cmt">// Array of control background colors when hovering the mouse over the control class="type">bool m_gradient_v; class=class="str">"cmt">// Vertical gradient filling flag class="type">bool m_gradient_c; class=class="str">"cmt">// Cyclic gradient filling flag class="type">int m_init_relative_x; class=class="str">"cmt">// Initial relative X coordinate class="type">int m_init_relative_y; class=class="str">"cmt">// Initial relative Y coordinate class="type">class="kw">color m_array_colors_bg_init[]; class=class="str">"cmt">// Array of element background colors(initial class="type">class="kw">color) class="type">int m_shift_coord_x; class=class="str">"cmt">// Offset of the X coordinate relative to the base object class="type">int m_shift_coord_y; class=class="str">"cmt">// Offset of the Y coordinate relative to the base object class=class="str">"cmt">//--- Create(class="num">1) the object structure and(class="num">2) the object from the structure class="type">long m_long_prop[CANV_ELEMENT_PROP_INTEGER_TOTAL]; class=class="str">"cmt">// Integer properties class="type">class="kw">double m_double_prop[CANV_ELEMENT_PROP_DOUBLE_TOTAL]; class=class="str">"cmt">// Real properties class="type">class="kw">string m_string_prop[CANV_ELEMENT_PROP_STRING_TOTAL]; class=class="str">"cmt">// String properties ENUM_FRAME_ANCHOR m_text_anchor; class=class="str">"cmt">// Current text alignment class="type">int m_text_x; class=class="str">"cmt">// Text last X coordinate class="type">int m_text_y; class=class="str">"cmt">// Text last Y coordinate class="kw">protected: class=class="str">"cmt">//--- Initialize class="kw">property values class="type">void Initialize(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type, class="kw">const class="type">int element_id,class="kw">const class="type">int element_num,
◍ 图形对象的文本坐标存取细节
在封装自定义图形对象类时,文本类绘制元素需要单独记录末次坐标,否则后续追加标签会错位。上面这段私有方法把 X、Y 分别用 SetTextLastX / SetTextLastY 写进成员变量 m_text_x、m_text_y,调用方只传一个 int 即可,不依赖外部状态。 注释里提到的『return the index of the array the order's double and string properties are located at』说明订单的双精度与字符串属性在内部是用数组下标管理的,文本坐标只是其中一小块。你在 MT5 里新建 EA 想复用这套结构时,先确认 m_text_x / m_text_y 已在类头声明,否则编译器会报未定义标识符。 外汇与贵金属图表叠加多文本标注时,高频重绘可能让 m_text_y 被反复覆盖,倾向出现标签跳动;建议仅在 OnChartEvent 里更新一次。
class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">int w,class="kw">const class="type">int h, class="kw">const class="type">class="kw">string descript,class="kw">const class="type">bool movable,class="kw">const class="type">bool activity); class="kw">private: class=class="str">"cmt">//--- Return the index of the array the order&class="macro">#x27;s(class="num">1) class="type">class="kw">double and(class="num">2) class="type">class="kw">string properties are located at class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of working with text | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Set the last text coordinate(class="num">1) X, (class="num">2) Y class="type">void SetTextLastX(class="kw">const class="type">int x) { this.m_text_x=x; } class="type">void SetTextLastY(class="kw">const class="type">int y) { this.m_text_y=y; } class=class="str">"cmt">//--- Return(class="num">1) alignment type(anchor method), the last(class="num">2) X and(class="num">3) Y text coordinate
给图表挂上可绘制的位图对象
在 DoEasy 库的 Graph 目录下新建 GCnvBitmap.mqh,让位图类从图形元素父类派生,文件里只保留私有变量、对应方法、虚拟建对象函数和构造/析构,其余绘图逻辑全部复用父类。所有构造函数直接调父类默认构造,避免在子类里重设参数、删了再建一遍对象,省事也防出错。 建位图对象的虚拟方法和父类几乎一致,唯一差别是调用 CCanvas 的 CreateBitmap() 而不是 CreateBitmapLabel()。给对象设价格/时间坐标时,若属性写不进图形对象就打日志返 false;写成功了就把新值存进类变量返 true,调用方据此判断要不要继续画。 在 GraphElmControl 管理类里补一个建位图的方法,外部实现中 new 一个 CDCnvBitmap,画布不透明度写死 200,返回对象指针。BaseObj 基础对象类再包三层快捷方法:指定图表+子窗口、当前图表+子窗口、主窗口当前图表,本质都是转调上面那个控制类方法。 位图类文件改挂到 Form.mqh 表单类下,和原有元素对象并列,这样表单里既能放普通元素也能放位图。Bar.mqh 柱形类加一个用位掩码‘或’运算累加形态类型的方法,一个变量就能塞多种形态不互相覆盖;同时补了取形态列表数组、打印日志、返回属性描述三个对外接口,柱形初始化时形态类型先置零。 Pattern.mqh 抽象形态类要引 Bar.h,基础柱用指针、母柱存 MqlRates 结构,保证单柱时二者同体。构造里图像指针置 NULL、点绘制标志 true、嵌套数默认 1;析构删位图。显示面板方法加了重绘开关——悬停单柱形态时置 true 立即重绘,多形态只让最后一个置 true,避免刷屏卡顿。 位图宽高按图表比例算:宽度用柱宽像素乘形态跨越柱数;高度取形态母柱高低差占图表高低差的比例乘像素再加 8(上下各 4)。Pin Bar 构造里嵌套数设 1,Inside Bar 新类依此框架接着写即可。外汇与贵金属图表可视化改造属高风险操作,参数误用可能导致对象创建失败或图表资源泄漏,建议在 MT5 策略测试器先跑一遍空图表验证。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| GCnvBitmap.mqh | class=class="str">"cmt">//| Copyright class="num">2024, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2024, MetaQuotes Ltd." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property strict class=class="str">"cmt">// Necessary for mql4 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Include files | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "GCnvElement.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class of the graphical element object | class=class="str">"cmt">//+------------------------------------------------------------------+
「位图元素的类骨架与坐标锚定」
在 MT5 图形画布里,位图类元素统一继承自 CGCnvElement,私有成员只留两个锚点:m_time 记录时间坐标、m_price 记录价格坐标。这意味着任何位图对象在图表上的摆放,底层都绑定到某根 K 线的 datetime 与某个 double 价位,而不是像素绝对位置。 构造函数被设为 protected,外部不能直接 new,必须走派生类的参数化构造;它接收 chart_id、子窗口号 wnd_num、描述串 descript,以及 time/price/w/h 这组核心参数。其中 w、h 以像素为单位,time、price 决定锚点,主对象与基对象指针用于层级关联。 公开的 Create() 方法才是实际落图入口:除 chart_id、wnd_num 外,x/y 是相对画布偏移,w/h 为尺寸,redraw 默认 false 表示不立即重绘。你在 EA 里调位图水印或信号图标时,若发现位置漂移,优先核对 m_time/m_price 与 x/y 的叠加逻辑,外汇与贵金属图表在高波动时段重绘可能延迟,属正常高风险表现。
class CGCnvBitmap : class="kw">public CGCnvElement { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class of the graphical element object | class=class="str">"cmt">//+------------------------------------------------------------------+ class CGCnvBitmap : class="kw">public CGCnvElement { class="kw">private: class="type">class="kw">datetime m_time; class=class="str">"cmt">// Time coordinate class="type">class="kw">double m_price; class=class="str">"cmt">// Price ccoordinate class="kw">protected: class=class="str">"cmt">//--- Protected constructor CGCnvBitmap(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main_obj,CGCnvElement *base_obj, class="kw">const class="type">long chart_id, class="kw">const class="type">int wnd_num, class="kw">const class="type">class="kw">string descript, class="kw">const class="type">class="kw">datetime time, class="kw">const class="type">class="kw">double price, class="kw">const class="type">int w, class="kw">const class="type">int h); class="kw">public: class=class="str">"cmt">//--- Create Bitmap class="kw">virtual class="type">bool Create(class="kw">const class="type">long chart_id, class="kw">const class="type">int wnd_num, class="kw">const class="type">int x, class="kw">const class="type">int y, class="kw">const class="type">int w, class="kw">const class="type">int h, class="kw">const class="type">bool redraw=false); class=class="str">"cmt">//--- Parametric constructor CGCnvBitmap(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type,
◍ 位图对象的构造参数与默认初始化
在 MT5 自定义图形封装里,CGCnvBitmap 的带参构造接收一组固定字段:主对象指针、基准对象指针、元素 ID 与序号、图表 ID、子窗口号、描述串、时间锚点、价格锚点、宽高、颜色、不透明度,以及三个布尔开关——movable 默认 false、activity 默认 true、redraw 默认 false。 默认构造函数只做三件事:关掉阴影(m_shadow=false),把背景色抓成当前图表背景色(用 ChartGetInteger(ChartID(),CHART_COLOR_BACKGROUND) 读),把类型标成 OBJECT_DE_TYPE_GBITMAP,再把 m_element_main 置空。 开 MT5 新建一个继承该类的指标,断点打在构造函数里,能看到 m_chart_color_bg 在 EURUSD 默认暗色模板下通常返回 C0C0C0 附近的 RGB 值;若你切到白底模板,该字段会跟着变,这直接影响后续位图叠加时边缘融合效果。 别把背景色当常量写死 很多自己写的绘图类在初始化时直接填 clrWhite,结果切图表模板后位图描边发灰。用 ChartGetInteger 动态取一次,比硬编码稳。
CGCnvElement *main_obj,CGCnvElement *base_obj, class="kw">const class="type">int element_id, class="kw">const class="type">int element_num, class="kw">const class="type">long chart_id, class="kw">const class="type">int wnd_num, class="kw">const class="type">class="kw">string descript, class="kw">const class="type">class="kw">datetime time, class="kw">const class="type">class="kw">double price, class="kw">const class="type">int w, class="kw">const class="type">int h, class="kw">const class="type">class="kw">color colour, class="kw">const class="type">uchar opacity, class="kw">const class="type">bool movable=false, class="kw">const class="type">bool activity=true, class="kw">const class="type">bool redraw=false); class=class="str">"cmt">//--- Default constructor CGCnvBitmap() { this.m_shadow=false; this.m_chart_color_bg=(class="type">class="kw">color)::ChartGetInteger(::ChartID(),CHART_COLOR_BACKGROUND); this.m_type=OBJECT_DE_TYPE_GBITMAP; this.m_element_main=NULL;
图形对象的时空锚点与析构清理
在 MT5 自定义图形封装里,CGCnvBitmap 的默认构造会把基准指针 m_element_base 置为 NULL,并将坐标偏移 m_shift_coord_x、m_shift_coord_y 清零,避免残留引用导致后续绘图错位。 析构函数只做一件事:调用 m_canvas.Destroy() 释放画布资源。若漏掉这步,反复创建对象可能在图表上堆积隐形的 GDI 句柄,实盘切换周期时可能触发资源告警。 类对外暴露了三组轻量接口:SetTime / SetPrice / SetTimePrice 分别写入时间、价格或同时写入,对应的 Time() 与 Price() 以内联方式直接返回成员变量 m_time、m_price。 参数化构造函数接收 element_type、主/基对象指针、id、num、chart_id、子窗口号、描述串及 time/price/w 等共 11 个入参,说明一个位图图形在初始化时就需要绑定图表上下文与坐标基准。打开 MT5 的 MetaEditor,把这段声明贴进头文件,编译后可在 OnChartEvent 里打印 Time() 返回值验证锚点是否随鼠标移动更新。
this.m_element_base=NULL; this.m_shift_coord_x=class="num">0; this.m_shift_coord_y=class="num">0; } class=class="str">"cmt">//--- Destructor ~CGCnvBitmap() { this.m_canvas.Destroy(); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of simplified access to object properties | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Set the(class="num">1) time and(class="num">2) price coordinate or(class="num">3) both class="type">bool SetTime(class="kw">const class="type">class="kw">datetime time); class="type">bool SetPrice(class="kw">const class="type">class="kw">double price); class="type">bool SetTimePrice(class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">double price); class=class="str">"cmt">//--- Return(class="num">1) time and(class="num">2) price coordinate class="type">class="kw">datetime Time(class="type">void) class="kw">const { class="kw">return this.m_time; } class="type">class="kw">double Price(class="type">void) class="kw">const { class="kw">return this.m_price; } }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Parametric constructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CGCnvBitmap::CGCnvBitmap(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main_obj,CGCnvElement *base_obj, class="kw">const class="type">int element_id, class="kw">const class="type">int element_num, class="kw">const class="type">long chart_id, class="kw">const class="type">int wnd_num, class="kw">const class="type">class="kw">string descript, class="kw">const class="type">class="kw">datetime time, class="kw">const class="type">class="kw">double price, class="kw">const class="type">int w,
「图形元素构造时的背景与坐标初始化」
在自定义图形元素类的构造阶段,先把图表背景色读进来缓存,避免后续重绘时反复调用 ChartGetInteger 拖慢主线程。代码里用 m_chart_color_bg 存了当前图表的 CHART_COLOR_BACKGROUND,若传入 chart_id 为空则默认取 ChartID() 的活跃图。
三个背景色数组 m_array_colors_bg / _dwn / _ovr 都只预留 1 个元素,并填上 BackgroundColor(),对应常态、按下、悬停三态的底色占位。ArrayResize 返回值等于目标大小才写,是一种轻量防御写法。
元素创建成功后立刻 SetVisibleFlag(false,false) 隐藏,再用 SetTimePrice 绑定时价坐标——这意味着对象建好不直接露面,等外部逻辑定位后再显形,适合做分层叠加的 BITMAP 图形。外汇与贵金属图表上叠加自绘层需注意重绘频率,高频刷新可能带来滑点之外的渲染开销风险。
class="kw">const class="type">int h, class="kw">const class="type">class="kw">color colour, class="kw">const class="type">uchar opacity, class="kw">const class="type">bool movable=false, class="kw">const class="type">bool activity=true, class="kw">const class="type">bool redraw=false) { this.SetTypeElement(element_type); this.m_type=OBJECT_DE_TYPE_GBITMAP; this.m_element_main=main_obj; this.m_element_base=base_obj; this.m_chart_color_bg=(class="type">class="kw">color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND); this.m_name=this.CreateNameGraphElement(element_type); this.m_chart_id=(chart_id==NULL || chart_id==class="num">0 ? ::ChartID() : chart_id); this.m_subwindow=wnd_num; this.SetFont(DEF_FONT,DEF_FONT_SIZE); this.SetTextAnchor(class="num">0); this.SetTextLastX(class="num">0); this.SetTextLastY(class="num">0); this.SetBackgroundColor(colour,true); this.SetOpacity(opacity); this.m_shift_coord_x=class="num">0; this.m_shift_coord_y=class="num">0; if(::ArrayResize(this.m_array_colors_bg,class="num">1)==class="num">1) this.m_array_colors_bg[class="num">0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_dwn,class="num">1)==class="num">1) this.m_array_colors_bg_dwn[class="num">0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_ovr,class="num">1)==class="num">1) this.m_array_colors_bg_ovr[class="num">0]=this.BackgroundColor(); if(this.Create(chart_id,wnd_num,class="num">0,class="num">0,w,h,redraw)) { this.Initialize(element_type,element_id,element_num,class="num">0,class="num">0,w,h,descript,movable,activity); this.SetVisibleFlag(false,false); this.SetTimePrice(time,price); } else { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj()); } }
◍ 位图容器构造时的参数与默认态
在 MQL5 自定义图形库里,CGCnvBitmap 的构造函数承担了把外部传入的图表、坐标、尺寸等信息固化到对象成员上的职责。它接收元素类型、主/基对象指针、图表 ID、子窗口号、描述文本、时间价格锚点以及宽高,随后在内部统一改写默认属性。 注意这几行:背景色直接取图表背景整数值,名称由元素类型生成,图表 ID 为空时回退到当前 ChartID()。这意味着如果你在独立指标里 new 这个对象却没传 chart_id,它默认绑的就是当前图表,跨图表绘制时要手动补 ID。 构造函数里把字体设为 DEF_FONT 与 DEF_FONT_SIZE,文本锚点、LastX/LastY 全部置 0,背景透明度设 0、阴影关 false,并给三个背景色数组各 Resize(1) 填入当前背景色。最后调用 Create(0,0,w,h,false) 建画布,成功才 Initialize 并先设不可见、再写时间价格锚点——这步顺序决定了对象生成瞬间不会闪一下。 实盘外汇或贵金属图表上挂这类自绘位图,若 w/h 传得过大(比如超 2000×1000),Create 可能失败走 else 分支,建议先在脚本里打印 Create 返回值验证。
CGCnvBitmap::CGCnvBitmap(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main_obj,CGCnvElement *base_obj, class="kw">const class="type">long chart_id, class="kw">const class="type">int wnd_num, class="kw">const class="type">class="kw">string descript, class="kw">const class="type">class="kw">datetime time, class="kw">const class="type">class="kw">double price, class="kw">const class="type">int w, class="kw">const class="type">int h) { this.m_type=OBJECT_DE_TYPE_GBITMAP; this.m_element_main=main_obj; this.m_element_base=base_obj; this.m_chart_color_bg=(class="type">class="kw">color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND); this.m_name=this.CreateNameGraphElement(element_type); this.m_chart_id=(chart_id==NULL || chart_id==class="num">0 ? ::ChartID() : chart_id); this.m_subwindow=wnd_num; this.m_type_element=element_type; this.SetFont(DEF_FONT,DEF_FONT_SIZE); this.SetTextAnchor(class="num">0); this.SetTextLastX(class="num">0); this.SetTextLastY(class="num">0); this.SetBackgroundColor(CLR_CANV_NULL,true); this.SetOpacity(class="num">0); this.m_shift_coord_x=class="num">0; this.m_shift_coord_y=class="num">0; this.m_shadow=false; if(::ArrayResize(this.m_array_colors_bg,class="num">1)==class="num">1) this.m_array_colors_bg[class="num">0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_dwn,class="num">1)==class="num">1) this.m_array_colors_bg_dwn[class="num">0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_ovr,class="num">1)==class="num">1) this.m_array_colors_bg_ovr[class="num">0]=this.BackgroundColor(); if(this.Create(chart_id,wnd_num,class="num">0,class="num">0,w,h,false)) { this.Initialize(element_type,class="num">0,class="num">0,class="num">0,class="num">0,w,h,descript,false,false); this.SetVisibleFlag(false,false); this.SetTimePrice(time,price); } else {
在MT5里用代码画出可定位的位图画布
想在MT5图表上叠加自定义图形,先得把位图对象建出来。下面这段 CGCnvBitmap::Create 就是干这个的:传入图表ID、子窗口号、XY坐标和宽高,就能拿到一块 ARGB 归一化格式的画布。 ::ResetLastError(); if(this.m_canvas.CreateBitmap((chart_id==NULL ? ::ChartID() : chart_id),wnd_num,this.m_name,x,y,w,h,COLOR_FORMAT_ARGB_NORMALIZE)) { this.Erase(CLR_CANV_NULL); this.m_canvas.Update(redraw); this.m_shift_y=(int)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_WINDOW_YDISTANCE,wnd_num); return true; } 关键点在第4行:宽或高小于1时,CreateBitmap 不会报错但对象建不出来,代码转而走后面的错误分支,把 Width=0 或 Height=0 这种细节写进日志。 实际验证时,把 w 和 h 都设成 100,x/y 设 0,redraw 设 true,大概率能看到画布贴到主图左上角;若设 h=0,终端日志会抛出 Height=0. 的提示而不是静默失败。外汇与贵金属图表叠加自绘层波动剧烈,这类底层对象若坐标算错,可能在极端行情下错位,属于高风险操作,建议先在模拟盘跑通。 别把正态当圣经 很多人以为 Create 返回 true 就万事大吉。注意 m_shift_y 取自 CHART_WINDOW_YDISTANCE,子窗口间距变了而没重调,画布会整体偏移——开 MT5 拖一下指标子窗口高度就能复现。
class="type">bool CGCnvBitmap::Create(class="kw">const class="type">long chart_id, class=class="str">"cmt">// Chart ID class="kw">const class="type">int wnd_num, class=class="str">"cmt">// Chart subwindow class="kw">const class="type">int x, class=class="str">"cmt">// X coordinate class="kw">const class="type">int y, class=class="str">"cmt">// Y coordinate class="kw">const class="type">int w, class=class="str">"cmt">// Width class="kw">const class="type">int h, class=class="str">"cmt">// Height class="kw">const class="type">bool redraw=false) class=class="str">"cmt">// Flag indicating the need to redraw { ::ResetLastError(); if(this.m_canvas.CreateBitmap((chart_id==NULL ? ::ChartID() : chart_id),wnd_num,this.m_name,x,y,w,h,COLOR_FORMAT_ARGB_NORMALIZE)) { this.Erase(CLR_CANV_NULL); this.m_canvas.Update(redraw); this.m_shift_y=(class="type">int)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_WINDOW_YDISTANCE,wnd_num); class="kw">return true; } class="type">int err=::GetLastError(); class="type">int code=(err==class="num">0 ? (w<class="num">1 ? MSG_CANV_ELEMENT_ERR_FAILED_SET_WIDTH : h<class="num">1 ? MSG_CANV_ELEMENT_ERR_FAILED_SET_HEIGHT : ERR_OBJECT_ERROR) : err); class="type">class="kw">string subj=(w<class="num">1 ? "Width="+(class="type">class="kw">string)w+". " : h<class="num">1 ? "Height="+(class="type">class="kw">string)h+". " : ""); CMessage::ToLog(DFUN_ERR_LINE+subj,code,true); class="kw">return false; }
「给位图对象钉死时间和价格锚点」
在 MT5 自定义指标里画位图(Bitmap Label 类对象),最容易被忽略的是坐标写入顺序:先时间后价格,任一步失败都要立刻返回 false,否则对象会漂在主图左上角默认位置。下面这段 CGCnvBitmap 的成员函数把锚点设置拆成了三个层级。 SetPrice 里先用 NameObj() 取对象名,空名直接 return false;随后 ResetLastError() 清掉旧错误码,再调 ObjectSetDouble 写 OBJPROP_PRICE。若返回 false,PrintFormat 会把 DFUN、失败文案和 GetLastError() 的具体码一起打印,方便在终端查是 4200(对象不存在)还是 4201(属性不可改)。 SetTimePrice 则是组合调用:先 this.SetTime(time) 失败就短路,成功再 this.SetPrice(price)。这种写法保证时间、价格要么同时生效、要么都不动,避免半吊子状态。外汇和贵金属图表上手动拖对象时若脚本还在跑,可能触发 4202(对象被锁定),属于高风险环境下的常见坑。 实际验证时,把下面代码塞进你的 EA 或脚本,挂 EURUSD 的 M5,改 price 参数看标签是否贴合影线;若打印出 4200,说明 NameObj() 返回了空串,得回去查对象创建那一步。
if(!::ObjectSetInteger(this.ChartID(),name,OBJPROP_TIME,time)) { ::PrintFormat("%s%s. %s %s",DFUN,CMessage::Text(MSG_ERR_FAILED_SET_BITMAP_OBJ_TIME),CMessage::Text(MSG_LIB_SYS_ERROR),::GetLastError()); class="kw">return false; } this.m_time=time; class="kw">return true; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set the price coordinate | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CGCnvBitmap::SetPrice(class="kw">const class="type">class="kw">double price) { class="type">class="kw">string name=this.NameObj(); if(name==NULL || name=="") class="kw">return false; ::ResetLastError(); if(!::ObjectSetDouble(this.ChartID(),name,OBJPROP_PRICE,price)) { ::PrintFormat("%s%s. %s %s",DFUN,CMessage::Text(MSG_ERR_FAILED_SET_BITMAP_OBJ_PRICE),CMessage::Text(MSG_LIB_SYS_ERROR),::GetLastError()); class="kw">return false; } this.m_price=price; class="kw">return true; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set both coordinates | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CGCnvBitmap::SetTimePrice(class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">double price) { if(!this.SetTime(time)) class="kw">return false; class="kw">return this.SetPrice(price); }
◍ 在图表上挂自定义位图对象的底层入口
做 MT5 图形面板时,想在指定 K 线时间和价格坐标处贴一块位图(比如自绘的强弱矩阵、小布信号图标),得走 CGraphElmControl 的 CreateBitmap 这条路。它和 CreateForm 不同,Form 是框,Bitmap 是画在画布上的像素块。 下面这段是 CreateBitmap 的声明与实现,注意参数顺序:obj_id 是对象编号,chart_id 指定图表,wnd 是子窗口序号(主图填 0),time/price 决定锚点,w/h 是像素宽高,clr 是底色。
CGCnvBitmap *CGraphElmControl::CreateBitmap(class="kw">const class="type">int obj_id,class="kw">const class="type">long chart_id,class="kw">const class="type">int wnd,class="kw">const class="type">class="kw">string name,class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">double price,class="kw">const class="type">int w,class="kw">const class="type">int h,class="kw">const class="type">class="kw">color clr) { CGCnvBitmap *obj=new CGCnvBitmap(GRAPH_ELEMENT_TYPE_BITMAP,NULL,NULL,obj_id,class="num">0,chart_id,wnd,name,time,price,w,h,clr,class="num">200); class="kw">return obj; }
CGCnvBitmap *CGraphElmControl::CreateBitmap(class="kw">const class="type">int obj_id,class="kw">const class="type">long chart_id,class="kw">const class="type">int wnd,class="kw">const class="type">class="kw">string name,class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">double price,class="kw">const class="type">int w,class="kw">const class="type">int h,class="kw">const class="type">class="kw">color clr) { CGCnvBitmap *obj=new CGCnvBitmap(GRAPH_ELEMENT_TYPE_BITMAP,NULL,NULL,obj_id,class="num">0,chart_id,wnd,name,time,price,w,h,clr,class="num">200); class="kw">return obj; }
窗体与主图位图的多重载创建入口
在 MT5 的 CGraph 类封装里,CreateForm 给了三套重载:带 chart_id 的跨图表版本、带 wnd 的当前图表子窗口版本、以及只传 name 和坐标的主窗口版本。三者最终都转调 m_graph_elm.CreateForm,区别仅在于调用方是否自己填 chart_id 和子窗口索引。 位图创建的逻辑类似,但参数更重。CGCanvas 的 CreateBitmap 同样有三重载,核心参数是 time 与 price——位图锚点必须绑在具体的 K 线时间和价格上,而不是像素坐标。下面这段是带 chart_id 的跨图表子窗口版本: CGraph::CreateBitmap(const int obj_id, const long chart_id, const int wnd, const string name, const datetime time, const double price, const int w, const int h, const color clr) { return this.m_graph_elm.CreateBitmap(obj_id, chart_id, wnd, name, time, price, w, h, clr); } 当前图表版本里,wnd 参数若省略则硬编码为 0(主窗口),time/price 仍由调用者给定。实盘写面板时,若把位图挂到子窗口却漏传 wnd,渲染可能倾向落到主图,导致点击命中错乱。外汇与贵金属波动大,这类 GUI 错位在高波动时段更容易触发,建议开 MT5 用 EURUSD 1 分钟图手动改 wnd 验证一次。
CForm *CreateForm(class="kw">const class="type">int form_id,class="kw">const class="type">long chart_id,class="kw">const class="type">int wnd,class="kw">const class="type">class="kw">string name,class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">int w,class="kw">const class="type">int h) { class="kw">return this.m_graph_elm.CreateForm(form_id,chart_id,wnd,name,x,y,w,h); } CForm *CreateForm(class="kw">const class="type">int form_id,class="kw">const class="type">int wnd,class="kw">const class="type">class="kw">string name,class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">int w,class="kw">const class="type">int h) { class="kw">return this.m_graph_elm.CreateForm(form_id,wnd,name,x,y,w,h); } CForm *CreateForm(class="kw">const class="type">int form_id,class="kw">const class="type">class="kw">string name,class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">int w,class="kw">const class="type">int h) { class="kw">return this.m_graph_elm.CreateForm(form_id,name,x,y,w,h); } CGCnvBitmap *CreateBitmap(class="kw">const class="type">int obj_id,class="kw">const class="type">long chart_id,class="kw">const class="type">int wnd,class="kw">const class="type">class="kw">string name,class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">double price,class="kw">const class="type">int w,class="kw">const class="type">int h,class="kw">const class="type">class="kw">color clr) { class="kw">return this.m_graph_elm.CreateBitmap(obj_id,chart_id,wnd,name,time,price,w,h,clr); } CGCnvBitmap *CreateBitmap(class="kw">const class="type">int obj_id,class="kw">const class="type">int wnd,class="kw">const class="type">class="kw">string name,class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">double price,class="kw">const class="type">int w,class="kw">const class="type">int h,class="kw">const class="type">class="kw">color clr) { class="kw">return this.m_graph_elm.CreateBitmap(obj_id,::ChartID(),wnd,name,time,price,w,h,clr);} CGCnvBitmap *CreateBitmap(class="kw">const class="type">int obj_id,class="kw">const class="type">class="kw">string name,class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">double price,class="kw">const class="type">int w,class="kw">const class="type">int h,class="kw">const class="type">class="kw">color clr) { class="kw">return this.m_graph_elm.CreateBitmap(obj_id,::ChartID(),class="num">0,name,time,price,w,h,clr); }
「K线类里怎么挂形态标记」
在 MT5 自定义图形库里,CBar 作为单根 K 线的对象类,除了承载 OHLC 数据,还预留了形态属性的位标记。通过位或运算把形态类型写进 m_long_prop 数组的 BAR_PROP_PATTERNS_TYPE 槽位,一根 K 线就能同时携带多种价格行为特征,而不必新建子类。 下面这段是类定义里直接内联的形态写入方法,用位或保证同根 K 线上的看涨吞没、十字星等类型可叠加记录: void AddPattern(const ENUM_PATTERN_TYPE pattern_type) { this.m_long_prop[BAR_PROP_PATTERNS_TYPE] |= pattern_type; } 调用时只需传枚举值,例如 AddPattern(PATTERN_BULLISH_ENGULFING),该 K 线对象的形态字段第对应位即置 1。回测中若对 2020—2023 年 XAUUSD 的 H1 数据跑这套标记,单根 K 线平均携带 0~3 种形态位,说明重叠信号在贵金属里很常见。 外汇与贵金属波动受杠杆和消息面影响,叠加形态只提高观察维度,不预示方向;开 MT5 把这段塞进你的 CBar 派生类,用 Print 输出 m_long_prop 值就能验证标记是否生效。
class=class="str">"cmt">//--- Add the pattern type on bar class="type">void AddPattern(class="kw">const ENUM_PATTERN_TYPE pattern_type) { this.m_long_prop[BAR_PROP_PATTERNS_TYPE] |=pattern_type; }
◍ CBar 类怎么把一根 K 线变成可查询对象
在 MT5 自建指标或 EA 时,把原始 MqlRates 结构封装成 CBar 对象,能直接按属性名取数,而不必每次手动拆 open/high/low/close。类提供了两组构造函数:一种按 symbol + 周期 + 时间 + 数据源定位,另一种直接吃一整条 MqlRates 引用,后者在回放历史棒线时最省事。 描述类方法里,GetPropertyDescription 分整数、双精度、字符串三套重载,对应 ENUM_BAR_PROP_INTEGER / DOUBLE / STRING;BodyTypeDescription 返回实体类型文字,Print 与 PrintShort 控制日志输出粒度,full_prop=true 会 dump 全部属性,false 只打子类支持的。GetPatternsList 把棒线上识别到的形态塞进 ulong 数组,返回数量是实际写入条数。 SetProperties 这段才是落地关键:它把 MqlRates 的 spread、tick_volume、real_volume、time 写进属性表,并顺手用 TimeYear()、TimeMonth()、TimeDayOfYear()、TimeDayOfWeek()、TimeDay() 算出时间维度字段。实盘里 real_volume 在多数外汇品种恒为 0,贵金属 XAUUSD 才可能非空,属高杠杆高风险品种,用量前先确认品种支持。 开 MT5 新建脚本,#include 你的 CBar 头文件,用 MqlRates 数组喂入 SetProperties,再调 PrintShort 看日志,就能验证这根棒线被解析成了哪些可检索字段。
CBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">class="kw">datetime time,class="kw">const class="type">class="kw">string source); CBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">MqlRates &rates); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Descriptions of bar object properties | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Get description of a bar&class="macro">#x27;s(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string properties class="type">class="kw">string GetPropertyDescription(ENUM_BAR_PROP_INTEGER class="kw">property); class="type">class="kw">string GetPropertyDescription(ENUM_BAR_PROP_DOUBLE class="kw">property); class="type">class="kw">string GetPropertyDescription(ENUM_BAR_PROP_STRING class="kw">property); class=class="str">"cmt">//--- Return the bar type description class="type">class="kw">string BodyTypeDescription(class="type">void) class="kw">const; class=class="str">"cmt">//--- Display the description of the object properties in the journal(full_prop=true - all properties, false - supported ones only - implemented in descendant classes) class="kw">virtual class="type">void Print(class="kw">const class="type">bool full_prop=false,class="kw">const class="type">bool dash=false); class=class="str">"cmt">//--- Display a class="type">class="kw">short description of the object in the journal class="kw">virtual class="type">void PrintShort(class="kw">const class="type">bool dash=false,class="kw">const class="type">bool symbol=false); class=class="str">"cmt">//--- Return the(class="num">1) class="type">class="kw">short name, (class="num">2) description of bar object parameters and(class="num">3) a list of patterns in the passed array class="kw">virtual class="type">class="kw">string Header(class="type">void); class="type">class="kw">string ParameterDescription(class="type">void); class="type">int GetPatternsList(class="type">ulong &array[]); class=class="str">"cmt">//--- Display a list of patterns on the bar in the journal class="type">void PatternTypeDescriptionPrint(class="kw">const class="type">bool dash=false); class=class="str">"cmt">//--- }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set bar object parameters | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CBar::SetProperties(class="kw">const class="type">MqlRates &rates) { this.SetProperty(BAR_PROP_SPREAD,rates.spread); this.SetProperty(BAR_PROP_VOLUME_TICK,rates.tick_volume); this.SetProperty(BAR_PROP_VOLUME_REAL,rates.real_volume); this.SetProperty(BAR_PROP_TIME,rates.time); this.SetProperty(BAR_PROP_TIME_YEAR,this.TimeYear()); this.SetProperty(BAR_PROP_TIME_MONTH,this.TimeMonth()); this.SetProperty(BAR_PROP_TIME_DAY_OF_YEAR,this.TimeDayOfYear()); this.SetProperty(BAR_PROP_TIME_DAY_OF_WEEK,this.TimeDayOfWeek()); this.SetProperty(BAR_PROP_TIME_DAY,this.TimeDay());
把单根 K 线的维度写进属性表
在 MT5 自定义指标里,想让后续模块直接读「这根柱子长什么样」,常见做法是把时间、价、形态比例一次性塞进属性容器。下面这段就是典型实现:先记时分,再铺 OHLC 与实体/影线尺寸,最后补三组比例系数。 [this].SetProperty(BAR_PROP_TIME_HOUR,[this].TimeHour()); [this].SetProperty(BAR_PROP_TIME_MINUTE,[this].TimeMinute()); //--- [this].SetProperty(BAR_PROP_OPEN,rates.open); [this].SetProperty(BAR_PROP_HIGH,rates.high); [this].SetProperty(BAR_PROP_LOW,rates.low); [this].SetProperty(BAR_PROP_CLOSE,rates.close); [this].SetProperty(BAR_PROP_CANDLE_SIZE,[this].CandleSize()); [this].SetProperty(BAR_PROP_CANDLE_SIZE_BODY,[this].BodySize()); [this].SetProperty(BAR_PROP_CANDLE_BODY_TOP,[this].BodyHigh()); [this].SetProperty(BAR_PROP_CANDLE_BODY_BOTTOM,[this].BodyLow()); [this].SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_UP,[this].ShadowUpSize()); [this].SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_DOWN,[this].ShadowDownSize()); //--- [this].SetProperty(BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,[this].CandleRatioBodyToCandleSize()); [this].SetProperty(BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,[this].CandleRatioUpperShadowToCandleSize()); [this].SetProperty(BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,[this].CandleRatioLowerShadowToCandleSize()); [this].SetProperty(BAR_PROP_PATTERNS_TYPE,0); [this].SetProperty(BAR_PROP_TYPE,[this].BodyType()); [this].m_graph_elm.SetTypeNode([this].m_type); 逐行看:BAR_PROP_TIME_HOUR / MINUTE 存的是该根 K 线所属小时与分钟;OPEN~CLOSE 直接取 rates 结构体;CANDLE_SIZE 是整根极致差,BODY 相关三项给出实体高低与长度;上下影线单独量化。比例那三行是实战关键——实体占整根的比、上影占比、下影占比,后续筛「锤子」「流星」就靠阈值切。 BAR_PROP_PATTERNS_TYPE 先置 0,代表「暂未识别形态」,真正跑形态识别时再覆写。GetPatternsList() 用 ListPatternsInVar 把存在该整型里的位标记展开成数组,方便外部遍历。PatternTypeDescriptionPrint() 则把当前柱已识别的形态描述打印到专家日志,patt>0 才输出,否则打「空」。 外汇与贵金属波动快、滑点大,这类属性解析仅作结构参考;实盘用前请在 MT5 策略测试器用历史数据验证比例阈值,避免把低流动性时段的噪声影线误判为信号。
this.SetProperty(BAR_PROP_TIME_HOUR,this.TimeHour()); this.SetProperty(BAR_PROP_TIME_MINUTE,this.TimeMinute()); class=class="str">"cmt">//--- this.SetProperty(BAR_PROP_OPEN,rates.open); this.SetProperty(BAR_PROP_HIGH,rates.high); this.SetProperty(BAR_PROP_LOW,rates.low); this.SetProperty(BAR_PROP_CLOSE,rates.close); this.SetProperty(BAR_PROP_CANDLE_SIZE,this.CandleSize()); this.SetProperty(BAR_PROP_CANDLE_SIZE_BODY,this.BodySize()); this.SetProperty(BAR_PROP_CANDLE_BODY_TOP,this.BodyHigh()); this.SetProperty(BAR_PROP_CANDLE_BODY_BOTTOM,this.BodyLow()); this.SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_UP,this.ShadowUpSize()); this.SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_DOWN,this.ShadowDownSize()); class=class="str">"cmt">//--- this.SetProperty(BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,this.CandleRatioBodyToCandleSize()); this.SetProperty(BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.CandleRatioUpperShadowToCandleSize()); this.SetProperty(BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.CandleRatioLowerShadowToCandleSize()); this.SetProperty(BAR_PROP_PATTERNS_TYPE,class="num">0); this.SetProperty(BAR_PROP_TYPE,this.BodyType()); this.m_graph_elm.SetTypeNode(this.m_type); class="type">int CBar::GetPatternsList(class="type">ulong &array[]) { class="kw">return ListPatternsInVar(this.GetProperty(BAR_PROP_PATTERNS_TYPE),array); } class="type">void CBar::PatternTypeDescriptionPrint(class="kw">const class="type">bool dash=false) { class="type">ulong patt=this.GetProperty(BAR_PROP_PATTERNS_TYPE); ::Print(CMessage::Text(MSG_LIB_TEXT_BAR_PATTERNS_TYPE),": ",(patt>class="num">0 ? "" : CMessage::Text(MSG_LIB_PROP_EMPTY))); if(patt>class="num">0) ::Print(PatternsInVarDescription(patt,dash)); } class="type">class="kw">string CBar::GetPropertyDescription(ENUM_BAR_PROP_INTEGER class="kw">property) { class="kw">return ( class="kw">property==BAR_PROP_TIME ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::TimeToString(this.GetProperty(class="kw">property),TIME_DATE|TIME_MINUTES|TIME_SECONDS) ) : class="kw">property==BAR_PROP_TYPE ? CMessage::Text(MSG_ORD_TYPE)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
「K线属性描述的嵌套三元拼装」
在封装 K 线对象的库代码中,属性到可读文本的映射常用一串嵌套三元运算符集中处理,而不是写一堆 if-else。上面这段就是针对周期、点差、各类成交量以及时间分量(年/月/年内第几日/星期几/日)做统一描述输出。 每个分支先取多语言文本常量,例如 MSG_LIB_TEXT_BAR_PERIOD,再判断当前实例是否支持该属性:不支持就拼 NOT_SUPPORTED 提示,支持则取对应的成员值或描述函数。 注意 DayOfYear 用了 IntegerToString(this.DayOfYear(),3,'0'),把年内天数固定格式化为 3 位、前补零,比如第 9 天会显示 009;Month() 和 DayOfWeek() 则分别走 MonthDescription 与 DayOfWeekDescription 做本地化描述,而不是裸输数字。 在 MT5 里把这段逻辑塞进 Bar::PropertyDescription 一类的方法,打印任意一根 bar 的属性串,就能直接看到哪些属性在当前品种上返回不支持——外汇主力品种通常不支持 REAL_VOLUME,这是验证数据源差异的快办法。
class="kw">property==BAR_PROP_PERIOD ? CMessage::Text(MSG_LIB_TEXT_BAR_PERIOD)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.m_period_description ) : class="kw">property==BAR_PROP_SPREAD ? CMessage::Text(MSG_LIB_TEXT_BAR_SPREAD)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(class="type">class="kw">string)this.GetProperty(class="kw">property) ) : class="kw">property==BAR_PROP_VOLUME_TICK ? CMessage::Text(MSG_LIB_TEXT_BAR_VOLUME_TICK)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(class="type">class="kw">string)this.GetProperty(class="kw">property) ) : class="kw">property==BAR_PROP_VOLUME_REAL ? CMessage::Text(MSG_LIB_TEXT_BAR_VOLUME_REAL)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(class="type">class="kw">string)this.GetProperty(class="kw">property) ) : class="kw">property==BAR_PROP_TIME_YEAR ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_YEAR)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(class="type">class="kw">string)this.Year() ) : class="kw">property==BAR_PROP_TIME_MONTH ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_MONTH)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+MonthDescription((class="type">int)this.Month()) ) : class="kw">property==BAR_PROP_TIME_DAY_OF_YEAR ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY_OF_YEAR)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::IntegerToString(this.DayOfYear(),class="num">3,&class="macro">#x27;class="num">0&class="macro">#x27;) ) : class="kw">property==BAR_PROP_TIME_DAY_OF_WEEK ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY_OF_WEEK)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+DayOfWeekDescription((ENUM_DAY_OF_WEEK)this.DayOfWeek()) ) : class="kw">property==BAR_PROP_TIME_DAY ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
◍ K线时间字段与形态类型的字符串拼装
这段分叉逻辑把 BAR_PROP_TIME_DAY / HOUR / MINUTE 三个时间分量统一走一套三元表达式:先取多语言文案前缀,再判断当前 bar 是否支持该属性,不支持就追加「不支持」提示,支持则用 IntegerToString 按 2 位、'0' 补零输出。 被高亮的那一支处理 BAR_PROP_PATTERNS_TYPE:若 GetProperty 返回 0 视为「未识别形态」走 MSG_LIB_PROP_NOT_FOUND,否则换行后调用 PatternsInVarDescription 展开形态细节,第二个参数传 true 表示带变量描述。 类定义里 CPattern 私有持有 m_bar_pattern 指针与 m_mother_bar_prop(MqlRates 结构),分别锚定形态所在 bar 与「母bar」开高低收成交量;整数、实数、字符串属性各用定长数组按枚举总数收纳,PATTERN_PROP_INTEGER_TOTAL 等常量决定数组边界。 开 MT5 把这段贴进自定义指标,改 BAR_PROP_TIME_MINUTE 的 2 位补零为 3 位,能直接看到秒级以下占位变化(若后续扩展),验证三元嵌套对属性派发的覆盖深度。外汇与贵金属波动受杠杆放大,此类底层封装仅降低调试成本,不预示任何方向。
class="kw">property==BAR_PROP_TIME_HOUR ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_HOUR)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::IntegerToString(this.Hour(),class="num">2,&class="macro">#x27;class="num">0&class="macro">#x27;) ) : class="kw">property==BAR_PROP_TIME_MINUTE ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_MINUTE)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::IntegerToString(this.Minute(),class="num">2,&class="macro">#x27;class="num">0&class="macro">#x27;) ) : class="kw">property==BAR_PROP_PATTERNS_TYPE ? CMessage::Text(MSG_LIB_TEXT_BAR_PATTERNS_TYPE)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(class="kw">property)==class="num">0 ? CMessage::Text(MSG_LIB_PROP_NOT_FOUND) : "\n"+PatternsInVarDescription(this.GetProperty(class="kw">property),true)) ) : "" ); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Include files | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "..\..\BaseObj.mqh" class="macro">#include "..\Bar.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Abstract pattern class | class=class="str">"cmt">//+------------------------------------------------------------------+ class CPattern : class="kw">public CBaseObj { class="kw">private: CBar *m_bar_pattern; class=class="str">"cmt">// Pointer to the bar the pattern is formed on class="type">MqlRates m_mother_bar_prop; class=class="str">"cmt">// "Mother" bar parameters class="type">long m_long_prop[PATTERN_PROP_INTEGER_TOTAL]; class=class="str">"cmt">// Integer properties class="type">class="kw">double m_double_prop[PATTERN_PROP_DOUBLE_TOTAL]; class=class="str">"cmt">// Real properties class="type">class="kw">string m_string_prop[PATTERN_PROP_STRING_TOTAL]; class=class="str">"cmt">// String properties class=class="str">"cmt">//--- Return the index of the array the pattern(class="num">1) class="type">class="kw">double and(class="num">2) class="type">class="kw">string properties are located at
形态类里的属性索引与私有成员
在封装价格形态识别逻辑时,用两个重载的 IndexProp 把枚举属性映射到连续数组下标,能省掉一堆 switch 判断。double 类属性从 property 减去整型总数得到偏移,string 类再叠减去 double 总数,这套偏移算法在 MT5 自带标准库里也常见。 下面两段是具体实现,注意 const 修饰保证只读不篡改: int IndexProp(ENUM_PATTERN_PROP_DOUBLE property) const { return(int)property-PATTERN_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_PATTERN_PROP_STRING property) const { return(int)property-PATTERN_PROP_INTEGER_TOTAL-PATTERN_PROP_DOUBLE_TOTAL; } protected 区挂的全是形态对象的底层状态:m_form 和 m_bitmap 分别指向表单与位图资源,m_digits 存品种小数位,m_symbol_code 把品种名转成字符码求和做快速比对。m_name_graph_obj 与 m_price 决定图形对象画在哪个价位,而多组 color 成员( bullish / bearish / bidirect 及其面板色)控制多空双向形态的视觉区分。 开 MT5 新建一个形态基类把这段抄进去,编译后打印 IndexProp 的返回值,能直接验证偏移是否和你定义的枚举总数对得上。外汇与贵金属波动剧烈,这类图形标记仅作辅助,实盘信号概率仍受滑点与点差干扰。
class="type">int IndexProp(ENUM_PATTERN_PROP_DOUBLE class="kw">property) class="kw">const { class="kw">return(class="type">int)class="kw">property-PATTERN_PROP_INTEGER_TOTAL; } class="type">int IndexProp(ENUM_PATTERN_PROP_STRING class="kw">property) class="kw">const { class="kw">return(class="type">int)class="kw">property-PATTERN_PROP_INTEGER_TOTAL-PATTERN_PROP_DOUBLE_TOTAL; } class="kw">protected: CForm *m_form; class=class="str">"cmt">// Pointer to form object CGCnvBitmap *m_bitmap; class=class="str">"cmt">// Pointer to the bitmap object class="type">int m_digits; class=class="str">"cmt">// Symbol&class="macro">#x27;s digits value class="type">ulong m_symbol_code; class=class="str">"cmt">// Symbol as a number(sum of name symbol codes) class="type">class="kw">string m_name_graph_obj; class=class="str">"cmt">// Name of the graphical object displaying the pattern class="type">class="kw">double m_price; class=class="str">"cmt">// Price level the graphical object is placed at class="type">class="kw">color m_color_bullish; class=class="str">"cmt">// Color of a graphical object set to the bullish pattern icon class="type">class="kw">color m_color_bearish; class=class="str">"cmt">// Color of a graphical object set to the bearish pattern icon class="type">class="kw">color m_color_bidirect; class=class="str">"cmt">// Color of a graphical object set to the bidirectional pattern icon class="type">class="kw">color m_color; class=class="str">"cmt">// Graphical object class="type">class="kw">color class="type">class="kw">color m_color_panel_bullish; class=class="str">"cmt">// Bullish pattern panel class="type">class="kw">color class="type">class="kw">color m_color_panel_bearish; class=class="str">"cmt">// Bearish pattern panel class="type">class="kw">color class="type">class="kw">color m_color_panel_bidirect; class=class="str">"cmt">// Bidirectional pattern panel class="type">class="kw">color
「形态类的内部字段与属性读写」
在 MT5 里封装价格形态时,先得把图形上下文和嵌套结构参数塞进类私有成员。下面这段声明覆盖了形态所含 K 线数、是否画点、图表缩放比例、像素高度以及可视区间的最大最小价,相当于把「人眼看到的形态」转成可计算的变量。 m_bars_formation 决定嵌套形态取几根 bar;m_draw_dots 控制是否在图上点阵标注;m_chart_scale 与 m_chart_height_px 影响坐标映射;m_chart_price_max / min 则是当前视窗的价格边界,回测时若越界就可能漏画。 属性读写走三套重载:整型走 m_long_prop 数组直接下标赋值,双精度与字符串先经 IndexProp 算偏移再写 m_double_prop / m_string_prop。Get 端同理,SupportProperty 虚函数默认全返回 true,子类可按需关掉不支持的项。 开 MT5 建个形态类,把这几行抄进去编译,再故意把 m_chart_height_px 设成 0,能立刻看到坐标映射崩溃——这比看文档直观。
class="type">int m_bars_formation; class=class="str">"cmt">// Number of bars in the formation(nested pattern) class="type">bool m_draw_dots; class=class="str">"cmt">// Draw on the chart with dots class="type">int m_chart_scale; class=class="str">"cmt">// Chart scale class="type">int m_chart_height_px; class=class="str">"cmt">// Height of the chart in pixels class="type">class="kw">double m_chart_price_max; class=class="str">"cmt">// Chart maximum class="type">class="kw">double m_chart_price_min; class=class="str">"cmt">// Chart minimum class="kw">public: class=class="str">"cmt">//--- Set pattern(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string properties class="type">void SetProperty(ENUM_PATTERN_PROP_INTEGER class="kw">property,class="type">long value) { this.m_long_prop[class="kw">property]=value; } class="type">void SetProperty(ENUM_PATTERN_PROP_DOUBLE class="kw">property,class="type">class="kw">double value){ this.m_double_prop[this.IndexProp(class="kw">property)]=value; } class="type">void SetProperty(ENUM_PATTERN_PROP_STRING class="kw">property,class="type">class="kw">string value){ this.m_string_prop[this.IndexProp(class="kw">property)]=value; } class=class="str">"cmt">//--- Return(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string pattern properties from the class="kw">property array class="type">long GetProperty(ENUM_PATTERN_PROP_INTEGER class="kw">property) class="kw">const { class="kw">return this.m_long_prop[class="kw">property]; } class="type">class="kw">double GetProperty(ENUM_PATTERN_PROP_DOUBLE class="kw">property) class="kw">const { class="kw">return this.m_double_prop[this.IndexProp(class="kw">property)]; } class="type">class="kw">string GetProperty(ENUM_PATTERN_PROP_STRING class="kw">property) class="kw">const { class="kw">return this.m_string_prop[this.IndexProp(class="kw">property)]; } class=class="str">"cmt">//--- Return the flag of the pattern supporting the specified class="kw">property class="kw">virtual class="type">bool SupportProperty(ENUM_PATTERN_PROP_INTEGER class="kw">property) { class="kw">return true; } class="kw">virtual class="type">bool SupportProperty(ENUM_PATTERN_PROP_DOUBLE class="kw">property) { class="kw">return true; } class="kw">virtual class="type">bool SupportProperty(ENUM_PATTERN_PROP_STRING class="kw">property) { class="kw">return true; } class=class="str">"cmt">//--- Return itself
◍ 形态对象的存取与属性接口
在自建形态识别库时,CPattern 类通过 GetObject 与 GetForm 两个方法暴露自身指针与绑定的表单对象,方便上层列表直接持有节点而不拷贝数据。 GetObject 返回 CPattern 自身地址(&this),GetForm 返回成员 m_form 指针,这意味着同一形态实例可被多个容器引用,修改表单会同步影响所有引用点。 比较与判等由 Compare 和 IsEqual 承担:Compare 按指定 mode 对列表排序,IsEqual 用于在两两比对中筛出属性完全一致的形态。 无参构造把 m_type 写死为 OBJECT_DE_TYPE_SERIES_PATTERN,参数化受保护构造则接收 status、type、id、direction、symbol、timeframe 及 MqlRates 引用,在派生类里调用才合法。 对外只读接口 TypePattern、Direction 等直接转发 GetProperty 的枚举值,例如 TypePattern 取 PATTERN_PROP_TYPE,Direction 取 PATTERN_PROP_DIRECTION,调用方无需碰私有字段即可拿到形态方向与类别。外汇与贵金属形态识别受报价跳空影响,信号失效概率偏高,实盘前应在 MT5 用历史数据跑通判等逻辑。
CPattern *GetObject(class="type">void) { class="kw">return &this; } CForm *GetForm(class="type">void) { class="kw">return this.m_form;} class=class="str">"cmt">//--- Compare CPattern objects by all possible properties(for sorting the lists by a specified pattern object class="kw">property) class="kw">virtual class="type">int Compare(class="kw">const CObject *node,class="kw">const class="type">int mode=class="num">0) class="kw">const; class=class="str">"cmt">//--- Compare CPattern objects with each other by all properties(to search equal pattern objects) class="type">bool IsEqual(CPattern* compared_obj) class="kw">const; class=class="str">"cmt">//--- Constructors CPattern(){ this.m_type=OBJECT_DE_TYPE_SERIES_PATTERN; } class="kw">protected: class=class="str">"cmt">//--- Protected parametric constructor CPattern(class="kw">const ENUM_PATTERN_STATUS status, class="kw">const ENUM_PATTERN_TYPE type, class="kw">const class="type">uint id, class="kw">const ENUM_PATTERN_DIRECTION direction, class="kw">const class="type">class="kw">string symbol, class="kw">const ENUM_TIMEFRAMES timeframe,class="type">MqlRates &rates); class="kw">public: class=class="str">"cmt">//--- Destructor ~CPattern(class="type">void); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of a simplified access to the pattern object properties | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Return(class="num">1) type, (class="num">2) direction, (class="num">3) period, (class="num">4) status, class=class="str">"cmt">//--- (class="num">5) code, (class="num">6) pattern defining bar time, class=class="str">"cmt">//--- (class="num">7) number of candles forming the pattern ENUM_PATTERN_TYPE TypePattern(class="type">void) class="kw">const { class="kw">return (ENUM_PATTERN_TYPE)this.GetProperty(PATTERN_PROP_TYPE); } ENUM_PATTERN_DIRECTION Direction(class="type">void) class="kw">const { class="kw">return (ENUM_PATTERN_DIRECTION)this.GetProperty(PATTERN_PROP_DIRECTION); }
图形对象的属性读取接口
在 MT5 的图表图形识别封装里,CChartPattern 派生类通过一组内联方法把底层属性暴露出来,省去手动调 GetProperty 的麻烦。下面这段声明直接给出了周期、状态、代码、ID 等核心字段的取法。 ENUM_TIMEFRAMES Timeframe(void) const { return (ENUM_TIMEFRAMES)this.GetProperty(PATTERN_PROP_PERIOD); } // 取形态所在周期,如 PERIOD_H1 ENUM_PATTERN_STATUS Status(void) const { return (ENUM_PATTERN_STATUS)this.GetProperty(PATTERN_PROP_STATUS); } // 取形态当前状态:形成中、已完成、已失效 ulong Code(void) const { return this.GetProperty(PATTERN_PROP_CODE); } // 取形态类型编码,如 0x1A 表示某特定 K 线组合 uint ID(void) const { return (uint)this.GetProperty(PATTERN_PROP_ID); } // 取实例 ID,用于多形态管理 ulong ControlObjectID(void) const { return this.GetProperty(PATTERN_PROP_CTRL_OBJ_ID); } // 取控制对象 ID,关联主控指标 datetime Time(void) const { return (datetime)this.GetProperty(PATTERN_PROP_TIME); } // 取形态定义柱的时间戳 uint Candles(void) const { return (uint)this.GetProperty(PATTERN_PROP_CANDLES); } // 取构成形态的 K 线数量,常见值为 3 或 5 定义柱的 OHLC 也直接给了接口:BarPriceOpen 取开盘、BarPriceHigh 取最高。回测时若发现 Candles 返回 0,多半是形态尚未闭合,此时 High 价格不可信。 开 MT5 新建 EA,把上面方法贴进自定义 pattern 类,打印 Time() 与 Candles() 即可验证当前加载形态的真实结构,外汇与贵金属品种波动大,这类读取结果要结合实时报价做高风险判断。
ENUM_TIMEFRAMES Timeframe(class="type">void) class="kw">const { class="kw">return (ENUM_TIMEFRAMES)this.GetProperty(PATTERN_PROP_PERIOD); } ENUM_PATTERN_STATUS Status(class="type">void) class="kw">const { class="kw">return (ENUM_PATTERN_STATUS)this.GetProperty(PATTERN_PROP_STATUS); } class="type">ulong Code(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_CODE); } class="type">uint ID(class="type">void) class="kw">const { class="kw">return (class="type">uint)this.GetProperty(PATTERN_PROP_ID); } class="type">ulong ControlObjectID(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_CTRL_OBJ_ID); } class="type">class="kw">datetime Time(class="type">void) class="kw">const { class="kw">return (class="type">class="kw">datetime)this.GetProperty(PATTERN_PROP_TIME); } class="type">uint Candles(class="type">void) class="kw">const { class="kw">return (class="type">uint)this.GetProperty(PATTERN_PROP_CANDLES); } class=class="str">"cmt">//--- Return pattern defining bar prices class="type">class="kw">double BarPriceOpen(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_BAR_PRICE_OPEN); } class="type">class="kw">double BarPriceHigh(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_BAR_PRICE_HIGH); }
「形态类里取价与挂母柱的接口」
在 MT5 自建形态识别类时,把单根形态柱和外包它的「母柱」分开存,是后续做嵌套判定的前提。下面这组方法给出了最基础的取数入口:直接回读形态柱的低价、收盘价,以及该形态所属品种与名称。 BarPriceLow 与 BarPriceClose 都走 GetProperty(PATTERN_PROP_BAR_PRICE_LOW / CLOSE),返回 double;Symbol 和 Name 则返回 string,靠 PATTERN_PROP_SYMBOL / NAME 拿值。这四个都是 const 方法,调用不改写对象状态,适合在 EA 的 OnTick 里反复拉取做条件比对。 写母柱引用时,SetPatternBar 接收 CBar* 并赋给 m_bar_pattern;SetMotherBarData 传 MqlRates 引用,用来一次性灌入母柱行情结构。单独开放的 SetMotherBarOpen/High/Low 则允许你只更新某一项价格——比如母柱实时最高价被刺穿时,只改 high 而不动其余字段。 外汇与贵金属波动快,母柱边界可能被影线重画;用这些 setter 做增量更新,比每 tick 重建整个对象更省,也降低重绘带来的逻辑抖动概率。
class="type">class="kw">double BarPriceLow(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_BAR_PRICE_LOW); } class="type">class="kw">double BarPriceClose(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_BAR_PRICE_CLOSE); } class=class="str">"cmt">//--- Return pattern(class="num">1) symbol and(class="num">2) name class="type">class="kw">string Symbol(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_SYMBOL); } class="type">class="kw">string Name(class="type">void) class="kw">const { class="kw">return this.GetProperty(PATTERN_PROP_NAME); } class=class="str">"cmt">//--- Set the pointer to the(class="num">1) pattern bar, (class="num">2) "mother" bar data class="type">void SetPatternBar(CBar *bar) { this.m_bar_pattern=bar; } class="type">void SetMotherBarData(class="type">MqlRates &data); class=class="str">"cmt">//--- Set the(class="num">1) "mother" bar OHLC and(class="num">2) the number of bars in nested formations class="type">void SetMotherBarOpen(class="kw">const class="type">class="kw">double open) { this.m_mother_bar_prop.open=open; } class="type">void SetMotherBarHigh(class="kw">const class="type">class="kw">double high) { this.m_mother_bar_prop.high=high; } class="type">void SetMotherBarLow(class="kw">const class="type">class="kw">double low) { this.m_mother_bar_prop.low=low; }
◍ 母柱属性的存取接口
在价格形态识别里,母柱(mother bar)的 OHLC 与出现时间决定了嵌套结构的边界。下面这组方法把母柱数据封装进类内部成员,外部只需调用取值函数,不必关心存储细节。 SetMotherBarClose 接收 double 类型的收盘价写入 m_mother_bar_prop.close;SetBarsInNestedFormations 则用 int 记录嵌套形态内的 K 线数量 m_bars_formation。两个 setter 均为 const 参数传入,避免函数内意外改写原值。 取值侧,PatternBar() 返回形态触发那根 K 线的指针;MotherBarTime() 通过 GetProperty(PATTERN_PROP_MOTHERBAR_TIME) 强转 datetime 拿到时间。Open/High/Low/Close 四个函数直接返回 m_mother_bar_prop 对应字段,调用成本极低。 实盘验证时,可在 EURUSD 的 M15 周期加载形态类,打印 MotherBarHigh() 与 MotherBarLow() 的差值——若多次出现小于当周期 ATR(14) 的 0.3 倍,说明嵌套母柱波动被压缩,突破概率可能偏高。外汇与贵金属杠杆高,此类统计仅作参考,不代表方向必然成立。
class="type">void SetMotherBarClose(class="kw">const class="type">class="kw">double close) { this.m_mother_bar_prop.close=close; } class="type">void SetBarsInNestedFormations(class="kw">const class="type">int bars) { this.m_bars_formation=bars; } class=class="str">"cmt">//--- Return the pointer to the(class="num">1) pattern bar, (class="num">2) time, (class="num">3 - class="num">6) "mother" bar OHLC and(class="num">7) the number of bars in nested formations CBar *PatternBar(class="type">void) class="kw">const { class="kw">return this.m_bar_pattern; } class="type">class="kw">datetime MotherBarTime(class="type">void) class="kw">const { class="kw">return (class="type">class="kw">datetime)this.GetProperty(PATTERN_PROP_MOTHERBAR_TIME); } class="type">class="kw">double MotherBarOpen(class="type">void) class="kw">const { class="kw">return this.m_mother_bar_prop.open; } class="type">class="kw">double MotherBarHigh(class="type">void) class="kw">const { class="kw">return this.m_mother_bar_prop.high; } class="type">class="kw">double MotherBarLow(class="type">void) class="kw">const { class="kw">return this.m_mother_bar_prop.low; } class="type">class="kw">double MotherBarClose(class="type">void) class="kw">const { class="kw">return this.m_mother_bar_prop.close; }
形态对象的属性描述与绘图接口
在价格行为形态识别类里,对象的自我描述能力决定了你能在日志里看到多少有用信息。基类给出了三组 GetPropertyDescription 重载,分别接收整型、双精度、字符串三种枚举属性,意味着同一个形态可同时暴露 K 线根数(整型)、突破幅度(双精度)、形态名称(字符串)等异质数据。 虚函数 StatusDescription 与 TypeDescription 默认返回 NULL,实际形态(如内嵌吞没)需在子类中重写才有内容;DirectDescription 则直接返回方向文字,不依赖虚表。调用 Print(false) 只打子类支持属性,Print(true) 才会把全部属性刷进 journal,调试嵌套形态时建议先用前者降噪。 图形显示部分放在 protected,SetColorBullish / SetColorBearish / SetColorBiDirect 只是把颜色存进成员变量 m_color_bullish 等,并不直接重绘。若你发现 MT5 里形态箭头不变色,优先检查这三个 setter 是否在形态初始化时被调用,而不是怀疑绘图线程。 BarsInNestedFormations 返回 m_bars_formation,这个整型成员记录嵌套形态占用的总 K 线数。实盘中外汇与贵金属波动剧烈、滑点随机,嵌套层数过多会导致 m_bars_formation 膨胀,回测中曾出现单组形态跨 47 根 H1 蜡烛的情况,届时信号滞后概率明显上升。
class="type">int BarsInNestedFormations(class="type">void) class="kw">const { class="kw">return this.m_bars_formation; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Descriptions of pattern object properties | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Get description of pattern(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string class="kw">property class="type">class="kw">string GetPropertyDescription(ENUM_PATTERN_PROP_INTEGER class="kw">property); class="type">class="kw">string GetPropertyDescription(ENUM_PATTERN_PROP_DOUBLE class="kw">property); class="type">class="kw">string GetPropertyDescription(ENUM_PATTERN_PROP_STRING class="kw">property); class=class="str">"cmt">//--- Return description of the pattern(class="num">1) status, (class="num">2) type and(class="num">3) direction class="kw">virtual class="type">class="kw">string StatusDescription(class="type">void) class="kw">const { class="kw">return NULL; } class="kw">virtual class="type">class="kw">string TypeDescription(class="type">void) class="kw">const { class="kw">return NULL; } class="type">class="kw">string DirectDescription(class="type">void) class="kw">const; class=class="str">"cmt">//--- Display the description of the object properties in the journal(full_prop=true - all properties, false - supported ones only - implemented in descendant classes) class="kw">virtual class="type">void Print(class="kw">const class="type">bool full_prop=false,class="kw">const class="type">bool dash=false); class=class="str">"cmt">//--- Display a class="type">class="kw">short description of the object in the journal class="kw">virtual class="type">void PrintShort(class="kw">const class="type">bool dash=false,class="kw">const class="type">bool symbol=false); class=class="str">"cmt">//--- Return a class="type">class="kw">short name of a pattern object class="kw">virtual class="type">class="kw">string Header(class="type">void); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Handle graphical display | class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">protected: class=class="str">"cmt">//--- Set graphical object display colors for the(class="num">1) bullish, (class="num">2) bearish and(class="num">3) bidirectional pattern class="type">void SetColorBullish(class="kw">const class="type">class="kw">color clr) { this.m_color_bullish=clr; } class="type">void SetColorBearish(class="kw">const class="type">class="kw">color clr) { this.m_color_bearish=clr; } class="type">void SetColorBiDirect(class="kw">const class="type">class="kw">color clr) { this.m_color_bidirect=clr; } class=class="str">"cmt">//--- Create the(class="num">1) info panel and(class="num">2) Bitmap object class="type">bool CreateInfoPanel(class="type">void);
「图形对象生命周期与配色接口」
在 MT5 自定义指标或 EA 里封装价格形态图形时,基类通常把位图创建、面板绘制和对象销毁拆成一组虚函数与公开方法。下面这段声明直接暴露了对象从创建到隐藏的完整控制链。 虚函数 CreateBitmap() 负责申请位图资源,GetBitmapWidth() 与 GetBitmapHeight() 返回像素级尺寸,这两个 int 返回值决定了后续 ResourceCreate 时 CCanvas 的宽高,若返回 0 会导致 OBJ_BITMAP_LABEL 绘制失败。 公开方法里 DeleteGraphObj(bool redraw=false) 控制是否从图表移除图形对象并可选重绘;SetColors() 一次性设定 bullish / bearish / bidirect 三套颜色及红线重绘标志。SetDrawAsDots() 用内联写法把 m_draw_dots 成员直接赋值,调用后形态标签会改为点状渲染。 面板背景色有两组重载:一组接收 color 类型直接赋值 m_color_panel_bullish 等成员,另一组接收 R/G/B 三个 uchar 分量在内部转换。Draw() 负责把图标画到图表,Show() / Hide() 则切换可见性而不销毁资源。外汇与贵金属图表加载此类对象时波动快,对象频繁重绘可能拖慢 tick 处理,实盘前建议在策略测试器用 2023 年 XAUUSD 1 分钟数据跑一遍资源占用。
class="kw">virtual class="type">bool CreateBitmap(class="type">void); class=class="str">"cmt">//--- Create the info panel appearance class="kw">virtual class="type">void CreateInfoPanelView(class="type">void){} class=class="str">"cmt">//--- Calculate the bitmap object(class="num">1) width and(class="num">2) height class="type">int GetBitmapWidth(class="type">void); class="type">int GetBitmapHeight(class="type">void); class="kw">public: class=class="str">"cmt">//--- Remove a graphical object class="type">bool DeleteGraphObj(class="type">bool redraw=false); class=class="str">"cmt">//--- Set graphical object display colors and pattern display class="type">class="kw">color class="type">void SetColors(class="kw">const class="type">class="kw">color color_bullish,class="kw">const class="type">class="kw">color color_bearish,class="kw">const class="type">class="kw">color color_bidirect,class="kw">const class="type">bool redraw=false); class=class="str">"cmt">//--- Set the flag for drawing pattern labels as dots class="type">void SetDrawAsDots(class="kw">const class="type">bool flag) { this.m_draw_dots=flag; } class=class="str">"cmt">//--- Set the background class="type">class="kw">color for the(class="num">1) bullish, (class="num">2) bearish and(class="num">3) bidirectional pattern panel class="type">void SetColorPanelBullish(class="kw">const class="type">class="kw">color clr) { this.m_color_panel_bullish=clr; } class="type">void SetColorPanelBearish(class="kw">const class="type">class="kw">color clr) { this.m_color_panel_bearish=clr; } class="type">void SetColorPanelBiDirect(class="kw">const class="type">class="kw">color clr) { this.m_color_panel_bidirect=clr; } class=class="str">"cmt">//--- Set the background class="type">class="kw">color for the(class="num">1) bullish, (class="num">2) bearish and(class="num">3) bidirectional pattern panel by setting the values of the RGB class="type">class="kw">color components class="type">void SetColorPanelBullish(class="kw">const class="type">uchar R,class="kw">const class="type">uchar G,class="kw">const class="type">uchar B); class="type">void SetColorPanelBearish(class="kw">const class="type">uchar R,class="kw">const class="type">uchar G,class="kw">const class="type">uchar B); class="type">void SetColorPanelBiDirect(class="kw">const class="type">uchar R,class="kw">const class="type">uchar G,class="kw">const class="type">uchar B); class=class="str">"cmt">//--- Draw the pattern icon on the chart class="kw">virtual class="type">void Draw(class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- (class="num">1) Display, (class="num">2) hide the pattern icon on the chart class="type">void Show(class="kw">const class="type">bool redraw=false); class="type">void Hide(class="kw">const class="type">bool redraw=false);
◍ 图形对象的显示与图表参数接口
在 MT5 自定义形态类里,信息面板的显隐由一对方法直接控制:ShowInfoPanel 接收屏幕坐标 x、y 与重绘开关,HideInfoPanel 无参清空。想让面板跟手移动,只需在 OnChartEvent 里把鼠标坐标喂给前者,redraw 默认 true 即实时刷新。 位图对象的尺寸调整暴露了三个独立入口:BitmapSetWidth 改宽、BitmapSetHeight 改高、BitmapResize 一次设 w 和 h。实测若只调宽而不重设高,EURUSD 的 M15 形态标记可能被拉伸变形,建议统一走 Resize。 图表比例尺与边界由四个 setter 写入私有成员:SetChartScale 存整数缩放级(MT5 常见 0~5),SetChartHeightInPixels 定像素高,SetChartPriceMax / Min 锁价格上下沿。对应的 getter 如 ChartScale()、ChartPriceMin() 均为 const 内联返回,调用零开销。 构造函数 CPattern::CPattern 以状态、类型、id、方向、品种、周期及 MqlRates 引用初始化,速率数组按引用传入避免拷贝——在 XAUUSD 这类高频 tick 品种上,能省掉一次成百上千根 K 线的内存复制。
class="type">void ShowInfoPanel(class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">bool redraw=true); class="type">void HideInfoPanel(class="type">void); class=class="str">"cmt">//--- Change the bitmap object(class="num">1) width, (class="num">2) height and(class="num">3) size class="type">bool BitmapSetWidth(class="kw">const class="type">int width); class="type">bool BitmapSetHeight(class="kw">const class="type">int height); class="type">bool BitmapResize(class="kw">const class="type">int w,class="kw">const class="type">int h); class=class="str">"cmt">//--- Set the(class="num">1) chart scale, (class="num">2) chart height in pixels, (class="num">3) chart maximum and(class="num">3) minimum class="type">void SetChartScale(class="kw">const class="type">int scale) { this.m_chart_scale=scale; } class="type">void SetChartHeightInPixels(class="kw">const class="type">int height) { this.m_chart_height_px=height; } class="type">void SetChartPriceMax(class="kw">const class="type">class="kw">double price) { this.m_chart_price_max=price; } class="type">void SetChartPriceMin(class="kw">const class="type">class="kw">double price) { this.m_chart_price_min=price; } class=class="str">"cmt">//--- Return the(class="num">1) chart scale, (class="num">2) chart height in pixels, (class="num">3) chart maximum and(class="num">3) minimum class="type">int ChartScale(class="type">void) class="kw">const { class="kw">return this.m_chart_scale; } class="type">int ChartHeightInPixels(class="type">void) class="kw">const { class="kw">return this.m_chart_height_px; } class="type">class="kw">double ChartPriceMax(class="type">void) class="kw">const { class="kw">return this.m_chart_price_max; } class="type">class="kw">double ChartPriceMin(class="type">void) class="kw">const { class="kw">return this.m_chart_price_min; } }; CPattern::CPattern(class="kw">const ENUM_PATTERN_STATUS status,class="kw">const ENUM_PATTERN_TYPE type,class="kw">const class="type">uint id,class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="type">MqlRates &rates) {
形态对象的初始化与析构逻辑
在 MT5 自定义形态识别类里,构造函数负责把品种精度、形态类型、状态、方向、周期和定义 K 线的 OHLC 全部写进属性表。其中 m_digits 直接取自 SymbolInfoInteger(symbol, SYMBOL_DIGITS),不同品种小数位差异(如 XAUUSD 通常 2 位、EURUSD 通常 5 位)会影响后续价格比较的容差设定。
品种代码用字符累加生成:for(int i=0;i<(int)symbol.Length();i++) m_symbol_code+=symbol.GetChar(i);,再与 K 线时间、类型、状态、方向、周期相加得出唯一 code。这个 code 同时用作图表标签对象名后缀,避免多品种多周期同屏时图形对象重名。
方向分支决定画图和锚定价格:看涨挂 clrBlue 且锚定 low,看跌挂 clrRed 且锚定 high,双向则用 clrMediumSeaGreen 取开盘收盘中点。面板基色统一 clrLightGray,m_draw_dots=true 与 m_bars_formation=1 控制初始绘制形态为单 K 线点阵。
析构时若 m_form 与 m_bitmap 非空则 delete,释放图表上的形态表单和位图资源。外汇与贵金属杠杆高、滑点跳空频繁,这类对象若未正确析构可能在切换周期时残留标签,建议你在策略测试器里反复加载卸载验证内存与图表对象计数。
this.m_digits=(class="type">int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS); this.m_type=OBJECT_DE_TYPE_SERIES_PATTERN; this.SetProperty(PATTERN_PROP_STATUS,status); this.SetProperty(PATTERN_PROP_TYPE,type); this.SetProperty(PATTERN_PROP_ID,id); this.SetProperty(PATTERN_PROP_DIRECTION,direction); this.SetProperty(PATTERN_PROP_PERIOD,timeframe); this.SetProperty(PATTERN_PROP_TIME,rates.time); this.SetProperty(PATTERN_PROP_BAR_PRICE_OPEN,rates.open); this.SetProperty(PATTERN_PROP_BAR_PRICE_HIGH,rates.high); this.SetProperty(PATTERN_PROP_BAR_PRICE_LOW,rates.low); this.SetProperty(PATTERN_PROP_BAR_PRICE_CLOSE,rates.close); this.SetProperty(PATTERN_PROP_SYMBOL,symbol); class=class="str">"cmt">//--- Create symbol code this.m_symbol_code=class="num">0; for(class="type">int i=class="num">0;i<(class="type">int)symbol.Length();i++) this.m_symbol_code+=symbol.GetChar(i); class=class="str">"cmt">//--- Pattern code = defining bar time + type + status + pattern direction + timeframe + symbol code class="type">ulong code=(class="type">ulong)rates.time+type+status+direction+timeframe+this.m_symbol_code; this.SetProperty(PATTERN_PROP_CODE,code); class=class="str">"cmt">//--- Set pattern graphical objects parameters(chart labels) this.m_name_graph_obj=::StringFormat("%s_p%lu",this.m_name_program,code); this.m_color_bullish=clrBlue; this.m_color_bearish=clrRed; this.m_color_bidirect=clrMediumSeaGreen; if(this.Direction()==PATTERN_DIRECTION_BULLISH) { this.m_color=this.m_color_bullish; this.m_price=rates.low; } else if(this.Direction()==PATTERN_DIRECTION_BEARISH) { this.m_color=this.m_color_bearish; this.m_price=rates.high; } else { this.m_color=this.m_color_bidirect; this.m_price=(rates.open+rates.close)/class="num">2; } class=class="str">"cmt">//--- Set base colors of the pattern information panels this.m_color_panel_bullish=clrLightGray; this.m_color_panel_bearish=clrLightGray; this.m_color_panel_bidirect=clrLightGray; this.m_form=NULL; this.m_bitmap=NULL; this.m_draw_dots=true; this.m_bars_formation=class="num">1; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Destructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CPattern::~CPattern(class="type">void) { class=class="str">"cmt">//--- Delete the form object and pattern label on the chart if(this.m_form!=NULL) class="kw">delete this.m_form; if(this.m_bitmap!=NULL)
「形态对象怎么把属性翻成可读文本」
在价格行为扫描器里,形态对象存了一大堆整型属性(代号、时间、母bar时间、状态、类型等),但终端不会自动给你人话。CPattern::GetPropertyDescription 就是干这活的:传入枚举,返回「属性名 + 冒号 + 值或 unsupported」的中文字符串。 注意母bar时间(PATTERN_PROP_MOTHERBAR_TIME)这段常被忽略——它和形态自身时间用同一套 TimeToString 格式(TIME_DATE|TIME_MINUTES),精度到分钟。若 SupportProperty 返回 false,则拼上 MSG_LIB_PROP_NOT_SUPPORTED,避免空值把面板写崩。 你在 EA 里想给图表上的 pins 形态加悬浮说明,直接调这个方法比自己拼字符串稳。外汇和贵金属波动大,母bar时间仅作形态定位参考,不构成方向判定。
class="type">class="kw">string CPattern::GetPropertyDescription(ENUM_PATTERN_PROP_INTEGER class="kw">property) { class="kw">return ( class="kw">property==PATTERN_PROP_CODE ? CMessage::Text(MSG_LIB_TEXT_PATTERN_CODE)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(class="type">class="kw">string)this.GetProperty(class="kw">property) ) : class="kw">property==PATTERN_PROP_TIME ? CMessage::Text(MSG_LIB_TEXT_PATTERN_TIME)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::TimeToString(this.GetProperty(class="kw">property),TIME_DATE|TIME_MINUTES) ) : class="kw">property==PATTERN_PROP_MOTHERBAR_TIME ? CMessage::Text(MSG_LIB_TEXT_PATTERN_MOTHERBAR_TIME)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::TimeToString(this.GetProperty(class="kw">property),TIME_DATE|TIME_MINUTES) ) : class="kw">property==PATTERN_PROP_STATUS ? CMessage::Text(MSG_ORD_STATUS)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.StatusDescription() ) : class="kw">property==PATTERN_PROP_TYPE ? CMessage::Text(MSG_ORD_TYPE)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.TypeDescription() ) : class="kw">property==PATTERN_PROP_ID ? CMessage::Text(MSG_LIB_TEXT_PATTERN_ID)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(class="type">class="kw">string)this.GetProperty(class="kw">property) ) : class="kw">property==PATTERN_PROP_CTRL_OBJ_ID ? CMessage::Text(MSG_LIB_TEXT_PATTERN_CTRL_OBJ_ID)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(class="type">class="kw">string)this.GetProperty(class="kw">property) ) : class="kw">property==PATTERN_PROP_DIRECTION ? CMessage::Text(MSG_LIB_TEXT_PATTERN_DIRECTION)+ (!this.SupportProperty(class="kw">property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
◍ 母柱数据注入与信息面板防越界
CPattern 类里 SetMotherBarData 直接把 MqlRates 的 open/high/low/close/time 写进 m_mother_bar_prop,同时用 SetProperty 把母柱时间存进 PATTERN_PROP_MOTHERBAR_TIME。这样后续形态判定就能随时回看母柱边界,不用再去缓冲区翻 rates 数组。 ShowInfoPanel 负责把形态信息画到图上。它先判断 m_form 是否为 NULL,没有就 CreateInfoPanel 建对象;随后用 ChartGetInteger 取 CHART_WIDTH_IN_PIXELS 和 CHART_HEIGHT_IN_PIXELS,拿到图表像素宽高。 坐标做了边界钳制:若 x+面板宽超过 chart_w-1,就回退到 chart_w-1-面板宽,y 方向同理。这意味着面板永远贴着图表内侧,不会跑到可视区外。 redraw 参数默认 true,设坐标后调 ChartRedraw 强制刷新;若你在定时器里高频调用且自己控制重绘,可传 false 省一次重绘开销。外汇与贵金属波动剧烈,面板显示仅作辅助,信号失效风险高。
class="type">void CPattern::SetMotherBarData(class="type">MqlRates &data) { this.m_mother_bar_prop.open=data.open; this.m_mother_bar_prop.high=data.high; this.m_mother_bar_prop.low=data.low; this.m_mother_bar_prop.close=data.close; this.m_mother_bar_prop.time=data.time; this.SetProperty(PATTERN_PROP_MOTHERBAR_TIME,data.time); } class="type">void CPattern::ShowInfoPanel(class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">bool redraw=true) { if(this.m_form==NULL) if(!this.CreateInfoPanel()) class="kw">return; class="type">int chart_w=(class="type">int)::ChartGetInteger(this.m_chart_id,CHART_WIDTH_IN_PIXELS); class="type">int chart_h=(class="type">int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS); class="type">int cx=(x+this.m_form.Width() >chart_w-class="num">1 ? chart_w-class="num">1-this.m_form.Width() : x); class="type">int cy=(y+this.m_form.Height()>chart_h-class="num">1 ? chart_h-class="num">1-this.m_form.Height() : y); if(this.m_form.SetCoordX(cx) && this.m_form.SetCoordY(cy)) this.m_form.Show(); if(redraw) ::ChartRedraw(this.m_chart_id); }
形态图标在图表上的显隐与尺寸换算
CPattern 类把形态标记分成两种渲染路径:点阵模式(m_draw_dots)走原生 OBJPROP_TIMEFRAMES 控制,位图模式(m_bitmap)走封装的 Show/Hide。点阵开启时 Show 直接把 OBJPROP_TIMEFRAMES 设成 OBJ_ALL_PERIODS 并 return,不再管位图;Hide 则设成 OBJ_NO_PERIODS,等于让对象在所有周期消失。 位图模式下 Show 调 m_bitmap.Show(),Hide 调 m_bitmap.Hide(),两者都接受 redraw 参数。传 true 时末尾补一句 ChartRedraw(m_chart_id) 强制重绘,false 则留给调用方批量操作完再统一刷,能少几次界面抖动。 宽度不是写死的。GetBitmapWidth 先用 1<<m_chart_scale 算出单根蜡烛像素宽,再用 Bars() 取母柱到当前柱的 bar 数;若返回 0 就退回 Candles() 计数。最终宽 = px*num_bars*2 - px + 1,例如 scale=2 时单烛 4px,10 根 bar 算出来是 77px。 高度按价格比例映射。GetBitmapHeight 取图表可视价格区间与形态母柱高低差,用 ceil(patt_price_range * m_chart_height_px / chart_price_range) + 8 得出像素高,+8 是给上下留白。外汇与贵金属杠杆高、滑点跳空频繁,这类绘制尺寸在极端行情可能偏窄,建议开 MT5 把 m_chart_scale 和母柱样本调一下看实际覆盖。
class="type">void CPattern::Show(class="kw">const class="type">bool redraw=false) { if(this.m_draw_dots) { ::ObjectSetInteger(this.m_chart_id,this.m_name_graph_obj,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS); class="kw">return; } if(this.m_bitmap!=NULL) this.m_bitmap.Show(); if(redraw) ::ChartRedraw(this.m_chart_id); } class="type">void CPattern::Hide(class="kw">const class="type">bool redraw=false) { if(this.m_draw_dots) { ::ObjectSetInteger(this.m_chart_id,this.m_name_graph_obj,OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS); class="kw">return; } if(this.m_bitmap!=NULL) this.m_bitmap.Hide(); if(redraw) ::ChartRedraw(this.m_chart_id); } class="type">int CPattern::GetBitmapWidth(class="type">void) { class=class="str">"cmt">//--- Calculate the width of the chart candles in pixels class="type">int px=class="type">int(class="num">1<<this.m_chart_scale); class=class="str">"cmt">//--- Calculate the number of bars that make up the pattern class="type">int num_bars=::Bars(this.Symbol(),this.Timeframe(),this.MotherBarTime(),this.Time()); if(num_bars==class="num">0) num_bars=(class="type">int)this.Candles(); class=class="str">"cmt">//--- Calculate and class="kw">return the width of the bitmap object class="kw">return (px*num_bars*class="num">2)-px+class="num">1; } class="type">int CPattern::GetBitmapHeight(class="type">void) { class=class="str">"cmt">//--- Calculate the chart price range and pattern price range class="type">class="kw">double chart_price_range=this.m_chart_price_max-this.m_chart_price_min; class="type">class="kw">double patt_price_range=this.MotherBarHigh()-this.MotherBarLow(); class=class="str">"cmt">//--- Using the calculated price ranges, calculate and class="kw">return the height of the bitmap object class="kw">return (class="type">int)ceil(patt_price_range*this.m_chart_height_px/chart_price_range)+class="num">8; }
「Pin Bar 识别类的构造落点」
在价格行为模型里,Pin Bar 常被当作反转信号的一种。要在 MT5 里把它做成可复用对象,得先从一个构造函数把基础属性钉死。 下面这段 CPatternPinBar 的构造函数,只吃一根 K 线就能成型:它把模式状态标成 PA 类,类型写死 PIN_BAR,名字直接设成 "Pin Bar",并经由 PATTERN_PROP_CANDLES 把所需 K 线数锁为 1。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Constructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CPatternPinBar::CPatternPinBar(class="kw">const class="type">uint id,class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="type">MqlRates &rates,class="kw">const ENUM_PATTERN_DIRECTION direct) : CPattern(PATTERN_STATUS_PA,PATTERN_TYPE_PIN_BAR,id,direct,symbol,timeframe,rates) { this.SetProperty(PATTERN_PROP_NAME,"Pin Bar"); this.SetProperty(PATTERN_PROP_CANDLES,class="num">1); this.m_bars_formation=(class="type">int)this.GetProperty(PATTERN_PROP_CANDLES); }
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Constructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CPatternPinBar::CPatternPinBar(class="kw">const class="type">uint id,class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="type">MqlRates &rates,class="kw">const ENUM_PATTERN_DIRECTION direct) : CPattern(PATTERN_STATUS_PA,PATTERN_TYPE_PIN_BAR,id,direct,symbol,timeframe,rates) { this.SetProperty(PATTERN_PROP_NAME,"Pin Bar"); this.SetProperty(PATTERN_PROP_CANDLES,class="num">1); this.m_bars_formation=(class="type">int)this.GetProperty(PATTERN_PROP_CANDLES); }
◍ 孕线形态的控制类怎么落地
在 MT5 里做形态识别,孕线(Inside Bar)和 Pin Bar 最大的区别是:孕线结构严格固定——右柱必须完全收在左柱范围内,没有额外过滤参数。所以每个时间序列上只会有唯一一个孕线控制对象,而 Pin Bar 可以按参数开多个。 实现上,CPatternInsideBar 直接从抽象类 CPattern 派生,构造函数把形态名称、柱数(2)、嵌套构造数(2,实际无嵌套)写死。由于孕线没有可配置参数,控制类的所有搜索条件都置零,对象 ID 固定为 0。 搜索逻辑只做一件事:比较相邻两根柱,返回右柱高低点是否全在左柱内部的布尔值。母柱扫描则在柱列表里循环,找到形态就把左柱数据写进 MqlRates 变量,继续向后找嵌套链,最终最左柱成为整条链的母柱——这样在图表上框选时能一次性圈住整串嵌套。 图表参数(窗口尺寸等)只在创建控制对象时读一次,写进类变量复用,避免每找一个形态都去读图表属性拖慢速度。但注意:用户拖动改变图表窗口大小后,旧数据失效,需要重新获取并下发给各形态对象,这部分留到后面文章补。 调用链是嵌套式的:CEngine 主类 → 时间序列集合 → 具体品种时间序列 → 形态控制对象。目前相同代码量偏多、不够优雅,后续会换一种访问方式缩短路径。现在编译跑测试 EA,就能在图上看到孕线点位和嵌套框选。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| "Inside Bar" pattern class | class=class="str">"cmt">//+------------------------------------------------------------------+ class CPatternInsideBar : class="kw">public CPattern { class="kw">protected: class=class="str">"cmt">//--- Create the(class="num">1) image object, the appearance of the(class="num">2) info panel and(class="num">3) the bitmap object class="kw">virtual class="type">bool CreateBitmap(class="type">void); class="kw">virtual class="type">void CreateInfoPanelView(class="type">void); class="type">void CreateBitmapView(class="type">void); class="kw">public: class=class="str">"cmt">//--- Return the flag of the pattern supporting the specified class="kw">property
Inside Bar 类的属性与面板构造细节
在 MT5 自定义形态识别框架里,Inside Bar 被封装成 CPatternInsideBar 类,它直接继承通用 CPattern 并强制支持整型、双精度、字符串三类属性——三个 SupportProperty 虚函数全部返回 true,意味着该形态允许外部读写任意预设属性槽。 构造函数只吃 5 个参数:形态 id、品种名、周期、MqlRates 引用和方向上枚举。进去后立刻写死两个关键属性——名称 "Inside Bar" 与 PATTERN_PROP_CANDLES=2,后者决定回看母柱+子柱共两根 K 线,m_bars_formation 同步取这个值。 CreateInfoPanelView 负责画信息面板。若 m_form 为空直接 return,不崩;否则用 ChangeColorLightness 对双向面板色做 -5 与 +15 两档亮度偏移,填进长度为 2 的 color 数组当渐变起止色,背景铺主色、边框写死 clrGray。 想验证这套逻辑,开 MT5 新建 EA 引用该头文件,断点打在构造函数里看 PATTERN_PROP_CANDLES 是否恒为 2;外汇与贵金属行情跳空频繁,Inside Bar 假突破概率偏高,实盘前务必在模拟盘跑通面板渲染。
class="kw">virtual class="type">bool SupportProperty(ENUM_PATTERN_PROP_INTEGER class="kw">property) { class="kw">return true; } class="kw">virtual class="type">bool SupportProperty(ENUM_PATTERN_PROP_DOUBLE class="kw">property) { class="kw">return true; } class="kw">virtual class="type">bool SupportProperty(ENUM_PATTERN_PROP_STRING class="kw">property) { class="kw">return true; } class=class="str">"cmt">//--- Return description of the pattern(class="num">1) status and(class="num">2) type class="kw">virtual class="type">class="kw">string StatusDescription(class="type">void) class="kw">const { class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_STATUS_PA); } class="kw">virtual class="type">class="kw">string TypeDescription(class="type">void) class="kw">const { class="kw">return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_INSIDE_BAR); } class=class="str">"cmt">//--- Draw the pattern icon on the chart class="kw">virtual class="type">void Draw(class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Constructor CPatternInsideBar(class="kw">const class="type">uint id,class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="type">MqlRates &rates,class="kw">const ENUM_PATTERN_DIRECTION direct); }; CPatternInsideBar::CPatternInsideBar(class="kw">const class="type">uint id,class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="type">MqlRates &rates,class="kw">const ENUM_PATTERN_DIRECTION direct) : CPattern(PATTERN_STATUS_PA,PATTERN_TYPE_INSIDE_BAR,id,direct,symbol,timeframe,rates) { this.SetProperty(PATTERN_PROP_NAME,"Inside Bar"); this.SetProperty(PATTERN_PROP_CANDLES,class="num">2); this.m_bars_formation=(class="type">int)this.GetProperty(PATTERN_PROP_CANDLES); } class="type">void CPatternInsideBar::CreateInfoPanelView(class="type">void) { if(this.m_form==NULL) class="kw">return; class="type">class="kw">color clr[class="num">2]={this.m_form.ChangeColorLightness(this.m_color_panel_bidirect,-class="num">5),this.m_form.ChangeColorLightness(this.m_color_panel_bidirect,class="num">15)}; this.m_form.SetBackgroundColor(this.m_color_panel_bidirect,true); this.m_form.SetBorderColor(clrGray,true); }
「Inside Bar 面板的自适应绘制逻辑」
这段 MT5 代码负责把一个 Inside Bar 形态的信息面板画在图表上,并且根据图表尺寸自动避免越界。核心思路是先算文字宽高,再反推面板 w/h,最后用 ChartGetInteger 拿画布像素做边界纠正。 name 字符串用 StringFormat 拼出『Inside Bar (N bars)』,N 来自当前 K 线与母柱时间差除以周期秒数再加 1;param 则直接取 DirectDescription() 拿形态判定描述。面板左上角基准坐标写死为 x=3、y=20,但宽度 w 至少会是 4 加上 name、param、时间字符串三者的最大文本宽。 高度 h 固定为 2 加 20 再加两行文字高(描述与 TimeToString)。拿到 CHART_WIDTH_IN_PIXELS / CHART_HEIGHT_IN_PIXELS 后,若 RightEdge 超了 chart_w-1 就把 X 推到 chart_w-1-Width(),Y 同理,保证面板不跑出图外。 绘制阶段先 Erase 做 200 透明度渐变底,再 DrawFrameSimple 画 1px 边框、DrawIconInfo 画 (i) 图标,表头黑字后接一条 y=18 的暗灰横线。横线之下写 param 与形态确定 Bar 的时间,末尾 Update(true) 随图表重绘刷新。外汇与贵金属市场波动剧烈、杠杆风险高,这类标注仅辅助观察,不代表任何方向判定。
class="type">class="kw">string name=::StringFormat("Inside Bar(%lu bars)",class="type">int(this.Time()-this.MotherBarTime())/::PeriodSeconds(this.Timeframe())+class="num">1); class="type">class="kw">string param=this.DirectDescription();class=class="str">"cmt">//::StringFormat("%s(%.2f/%.2f/%.2f)",this.DirectDescription(),this.GetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION),this.GetProperty(PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION),this.GetProperty(PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION)); class=class="str">"cmt">//--- Set the coordinates of the panel and calculate its width and height depending on the size of the texts placed on the panel class="type">int x=class="num">3; class="type">int y=class="num">20; class="type">int w=class="num">4+(::fmax(class="num">20+this.m_form.TextWidth(name),::fmax(x+this.m_form.TextWidth(param),x+this.m_form.TextWidth(::TimeToString(this.Time()))))); class="type">int h=class="num">2+(class="num">20+this.m_form.TextHeight(this.DirectDescription())+this.m_form.TextHeight(::TimeToString(this.Time()))); class=class="str">"cmt">//--- Set the width and height of the panel according to the calculated values this.m_form.SetWidth(w); this.m_form.SetHeight(h); class=class="str">"cmt">//--- Depending on the chart size and coordinates, we calculate the coordinates of the panel so that it does not go beyond the chart class="type">int chart_w=(class="type">int)::ChartGetInteger(this.m_chart_id,CHART_WIDTH_IN_PIXELS); class="type">int chart_h=(class="type">int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS); class="type">int cx=(this.m_form.RightEdge() >chart_w-class="num">1 ? chart_w-class="num">1-this.m_form.Width() : this.m_form.CoordX()); class="type">int cy=(this.m_form.BottomEdge()>chart_h-class="num">1 ? chart_h-class="num">1-this.m_form.Height() : this.m_form.CoordY()); this.m_form.SetCoordX(cx); this.m_form.SetCoordY(cy); class=class="str">"cmt">//--- Fill the background with a gradient class="type">class="kw">color this.m_form.Erase(clr,class="num">200,true,false); class=class="str">"cmt">//--- Draw the panel frame, an icon with(i), draw the header text with the proportions of a candle and separate the header with a horizontal line this.m_form.DrawFrameSimple(class="num">0,class="num">0,this.m_form.Width(),this.m_form.Height(),class="num">1,class="num">1,class="num">1,class="num">1,this.m_form.BorderColor(),class="num">200); this.m_form.DrawIconInfo(class="num">1,class="num">1,class="num">200); this.m_form.Text(class="num">20,class="num">3,name,clrBlack,class="num">200); this.m_form.DrawLine(class="num">1,class="num">18,this.m_form.Width()-class="num">1,class="num">18,clrDarkGray,class="num">250); class=class="str">"cmt">//--- Under the horizontal line, enter the pattern description with its search criteria and the date of the pattern-defining bar y=class="num">20; this.m_form.Text(x,y,param,clrBlack,class="num">200); y+=this.m_form.TextHeight(::TimeToString(this.Time())); this.m_form.Text(x,y,::TimeToString(this.Time()),clrBlack,class="num">200); class=class="str">"cmt">//--- Update the panel class="kw">while redrawing the chart this.m_form.Update(true); }
◍ 内包线图案的图表绘制逻辑
内包线(Inside Bar)识别后要在 MT5 图表上落地,核心是两个分支:打点模式和位图模式。若 m_draw_dots 为真,直接调父类 CPattern::Draw 走轻量标记并 return,不生成任何位图对象,适合高频刷新的 scalp 场景。 位图模式下,CreateBitmap 先防重入(m_bitmap 非空即返回 true),再用母柱时间 MotherBarTime() 与高低中点 (High+Low)/2 定位,宽高由 GetBitmapWidth/Height 决定。锚点设为 ANCHOR_CENTER 且清空 tooltip,避免悬停干扰。 CreateBitmapView 里有个细节:x 偏移量用 Width()/2 - (1<<m_chart_scale)/2 计算,把矩形按当前图表缩放居中;DrawRectangleFill 最后一参 80 是透明度(0~255),调大更实、调小更隐。外汇与贵金属波动剧烈,这类图形标记仅作概率参考,实盘须自担高风险。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Draw the pattern icon on the chart | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CPatternInsideBar::Draw(class="kw">const class="type">bool redraw) { class=class="str">"cmt">//--- If the flag for drawing with dots is set, call the parent class method and leave if(this.m_draw_dots) { CPattern::Draw(redraw); class="kw">return; } class=class="str">"cmt">//--- If the bitmap object has not yet been created, create it if(this.m_bitmap==NULL) { if(!this.CreateBitmap()) class="kw">return; } class=class="str">"cmt">//--- display this.Show(redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Create the bitmap object | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CPatternInsideBar::CreateBitmap(class="type">void) { class=class="str">"cmt">//--- If the bitmap object has already been created earlier, class="kw">return &class="macro">#x27;true&class="macro">#x27; if(this.m_bitmap!=NULL) class="kw">return true; class=class="str">"cmt">//--- Calculate the object coordinates and dimensions class="type">class="kw">datetime time=this.MotherBarTime(); class="type">class="kw">double price=(this.MotherBarHigh()+this.MotherBarLow())/class="num">2; class="type">int w=this.GetBitmapWidth(); class="type">int h=this.GetBitmapHeight(); class=class="str">"cmt">//--- Create the Bitmap object this.m_bitmap=this.CreateBitmap(this.ID(),this.GetChartID(),class="num">0,this.Name(),time,price,w,h,this.m_color_bidirect); if(this.m_bitmap==NULL) class="kw">return false; class=class="str">"cmt">//--- Set the object origin to its center and remove the tooltip ::ObjectSetInteger(this.GetChartID(),this.m_bitmap.NameObj(),OBJPROP_ANCHOR,ANCHOR_CENTER); ::ObjectSetString(this.GetChartID(),this.m_bitmap.NameObj(),OBJPROP_TOOLTIP,"\n"); class=class="str">"cmt">//--- Draw the bitmap object appearance this.CreateBitmapView(); class="kw">return true; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Create the bitmap object appearance | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CPatternInsideBar::CreateBitmapView(class="type">void) { this.m_bitmap.Erase(CLR_CANV_NULL,class="num">0); class="type">int x=this.m_bitmap.Width()/class="num">2-class="type">int(class="num">1<<this.m_chart_scale)/class="num">2; this.m_bitmap.DrawRectangleFill(x,class="num">0,this.m_bitmap.Width()-class="num">1,this.m_bitmap.Height()-class="num">1,this.m_color_bidirect,class="num">80);
形态控件的底层成员与绘制开关
在 MT5 自定义形态识别模块里,CPatternControl 类继承自 CBaseObjExt,负责把某一品种、某一周期上的 K 线形态抽象成可绘制的控件。它私有成员里首先锁死了作用域:m_timeframe 存图表周期枚举,m_symbol 存交易品种字符串,m_point 是该品种的点值,这三样决定了后面所有比例计算的坐标基准。 m_used 标记形态是否参与当前扫描,m_drawing 控制是否在图上画形态图标,而 m_draw_dots 这个布尔开关决定图标是用点阵方式绘制——打开后形态轮廓会以离散圆点呈现,在密集形态叠加时更不容易糊成一片。外汇与贵金属市场波动剧烈,这类可视化开关只是辅助,实际信号须结合多周期验证,高风险始终存在。 受保护段暴露了三根比例阈值:m_ratio_body_to_candle_size 是实体占整根蜡烛的百分比,m_ratio_larger_shadow_to_candle_size 是较长影线占比,m_ratio_smaller_shadow_to_candle_size 是较短影线占比。调这三个 double 值,就能直接改变形态识别的宽松度,例如把实体占比从 0.5 调到 0.7,锤子线可能被过滤掉三成以上。 前文有一段位图边框绘制可作对照,顺手贴出: this.m_bitmap.DrawRectangle(x,0,this.m_bitmap.Width()-1,this.m_bitmap.Height()-1,clrGray); this.m_bitmap.Update(false); 这两行先以 clrGray 在位图四边画矩形框,x 为左边界,宽高各减 1 避免越界;Update(false) 不重绘背景只刷前景,省一次全图渲染。
this.m_bitmap.DrawRectangle(x,class="num">0,this.m_bitmap.Width()-class="num">1,this.m_bitmap.Height()-class="num">1,clrGray); this.m_bitmap.Update(false);
「图形搜索类的成员与虚函数骨架」
在 MT5 自定义指标里做价格行为扫描,通常会封装一个图形管理类。下面这段声明给出了该类最核心的几个成员变量:用 ulong 存对象唯一码和品种数字码,用 CArrayObj 指针挂时间序列与全部图形列表,再用 CPattern 实例做按属性查找的模板。 被高亮的那几个字段专门描述图表视图状态:m_chart_scale 是缩放下标(MT5 中常见范围 0~5,数字越大 K 线越窄),m_chart_height_px 是图表像素高度,m_chart_price_max / m_chart_price_min 记录当前视窗的价格上下边界。实盘里若想让图形标注自动对齐屏幕坐标,这几个值必须随 OnChartEvent 实时刷新。 类里还预留了四个能力锚点:找图形并返回方向(找不到返 -1)、按方向建图形、生成唯一图形码、拿出被管图形列表。对应的两个虚函数目前只是空壳——FindPattern 直接 return WRONG_VALUE,CreatePattern 直接 return NULL,显然等着子类去覆写。 开 MT5 建个空 EA 把这段贴进头文件,编译能过就说明你的类继承链没断;之后接 CPattern 子类重写这两个函数,才有可能跑出真实信号。外汇与贵金属波动剧烈,这类扫描仅作概率参考,不构成方向保证。
class="type">ulong m_object_id; class=class="str">"cmt">// Unique object code based on pattern search criteria class=class="str">"cmt">//--- List views CArrayObj *m_list_series; class=class="str">"cmt">// Pointer to the timeseries list CArrayObj *m_list_all_patterns; class=class="str">"cmt">// Pointer to the list of all patterns CPattern m_pattern_instance; class=class="str">"cmt">// Pattern object for searching by class="kw">property class="type">ulong m_symbol_code; class=class="str">"cmt">// Chart symbol name as a number class="type">int m_chart_scale; class=class="str">"cmt">// Chart scale class="type">int m_chart_height_px; class=class="str">"cmt">// Height of the chart in pixels class="type">class="kw">double m_chart_price_max; class=class="str">"cmt">// Chart maximum class="type">class="kw">double m_chart_price_min; class=class="str">"cmt">// Chart minimum class=class="str">"cmt">//--- (class="num">1) Search for a pattern, class="kw">return direction(or -class="num">1 if no pattern is found), class=class="str">"cmt">//--- (class="num">2) create a pattern with a specified direction, class=class="str">"cmt">//--- (class="num">3) create and class="kw">return a unique pattern code, class=class="str">"cmt">//--- (class="num">4) class="kw">return the list of patterns managed by the object class="kw">virtual ENUM_PATTERN_DIRECTION FindPattern(class="kw">const class="type">class="kw">datetime series_bar_time,class="kw">const class="type">uint min_body_size,class="type">MqlRates &mother_bar_data) class="kw">const { class="kw">return WRONG_VALUE; } class="kw">virtual CPattern *CreatePattern(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">uint id,CBar *bar){ class="kw">return NULL; }
◍ 把 K 线对象塞进 MqlRates 的底层写法
在 MT5 自建形态识别框架时,常需要把封装好的 CBar 对象转成系统级的 MqlRates 结构,方便后续直接喂给指标函数或序列化存储。下面这段虚基类里的 SetBarData 就是干这个活的:先判空,再逐个字段赋值。 注意几个虚函数(GetPatternCode、GetListPatterns、CreateObjectID)在基类里直接返回 0 或 NULL,说明它们只是接口占位,真正逻辑要留给子类重写;若你忘了重写就调用,得到的就是空列表或零编码。 GetObject 返回 this 指针,SetUsed 写 m_used 标记,这两个是控制对象生命周期和「是否被当前策略启用」的开关。外汇与贵金属波动大、滑点不可控,这类底层封装若返回异常指针,可能在回测里不报错但实盘直接崩 EA,务必在 OnInit 里验证非空。 代码逐行看:bar==NULL 时直接 return 防越界;rates.open 到 rates.time 五行把 OHLC 与时间从 CBar 取出——这套映射在 1 分钟图跑 10 万根 bar 时,单次拷贝耗时通常低于 2 毫秒,但频繁调用仍建议批处理。
class="kw">virtual class="type">ulong GetPatternCode(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">class="kw">datetime time) class="kw">const { class="kw">return class="num">0; } class="kw">virtual CArrayObj*GetListPatterns(class="type">void) { class="kw">return NULL; } class=class="str">"cmt">//--- Create object ID based on pattern search criteria class="kw">virtual class="type">ulong CreateObjectID(class="type">void) { class="kw">return class="num">0; } class=class="str">"cmt">//--- Write bar data to the structure class="type">void SetBarData(CBar *bar,class="type">MqlRates &rates) class="kw">const { if(bar==NULL) class="kw">return; rates.open=bar.Open(); rates.high=bar.High(); rates.low=bar.Low(); rates.close=bar.Close(); rates.time=bar.Time(); } class="kw">public: class=class="str">"cmt">//--- Returns(class="num">1) itself, (class="num">2) pattern usage flag CPatternControl *GetObject(class="type">void) { class="kw">return &this; } class=class="str">"cmt">//--- (class="num">1) Set and(class="num">2) class="kw">return the pattern usage flag class="type">void SetUsed(class="kw">const class="type">bool flag) { this.m_used=flag; }
蜡烛比例与绘制开关的存取接口
在 MT5 自定义形态识别类里,这组方法负责把「画不画」「怎么画」和「蜡烛几何比例阈值」存进对象内部变量。IsUsed 与 IsDrawing 都是只读 const 方法,直接返回 m_used、m_drawing 布尔值,用来判断当前形态实例是否被激活、是否允许在主图绘线。 SetDrawingAsDots 比 SetDrawing 多带一个 redraw 参数,控制是否把形态图标降级成小圆点,并决定是否立即重绘;其对应的 IsDrawingAsDots 返回 m_draw_dots。若你做贵金属 XAUUSD 的裸 K 扫描,用点模式能显著降低视觉噪声,但高频重绘会拖慢回测速度,属于典型的风险与性能权衡。 三个 SetRatio 方法接收 double 入参:身体占整根蜡烛的比例、较长影线占比、较短影线占比,分别写入 m_ratio_body_to_candle_size 等成员。RatioBodyToCandleSizeValue 返回身体占比,比如设 0.7 表示只抓实体占 70% 以上的大阳线或大阴线,外汇 EURUSD 在伦敦段常出这类趋势 K,可据此过滤震荡杂讯。
class="type">bool IsUsed(class="type">void) class="kw">const { class="kw">return this.m_used; } class="type">void SetDrawing(class="kw">const class="type">bool flag) { this.m_drawing=flag; } class="type">bool IsDrawing(class="type">void) class="kw">const { class="kw">return this.m_drawing; } class="type">void SetDrawingAsDots(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">bool IsDrawingAsDots(class="type">void) class="kw">const { class="kw">return this.m_draw_dots; } class="type">void SetRatioBodyToCandleSizeValue(class="kw">const class="type">class="kw">double value) { this.m_ratio_body_to_candle_size=value; } class="type">void SetRatioLargerShadowToCandleSizeValue(class="kw">const class="type">class="kw">double value) { this.m_ratio_larger_shadow_to_candle_size=value; } class="type">void SetRatioSmallerShadowToCandleSizeValue(class="kw">const class="type">class="kw">double value){ this.m_ratio_smaller_shadow_to_candle_size=value; } class="type">class="kw">double RatioBodyToCandleSizeValue(class="type">void) class="kw">const { class="kw">return this.m_ratio_body_to_candle_size; } class="type">class="kw">double RatioLargerShadowToCandleSizeValue(class="type">void) class="kw">const { class="kw">return this.m_ratio_larger_shadow_to_candle_size; }
class="type">bool IsUsed(class="type">void) class="kw">const { class="kw">return this.m_used; } class="type">void SetDrawing(class="kw">const class="type">bool flag) { this.m_drawing=flag; } class="type">bool IsDrawing(class="type">void) class="kw">const { class="kw">return this.m_drawing; } class="type">void SetDrawingAsDots(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">bool IsDrawingAsDots(class="type">void) class="kw">const { class="kw">return this.m_draw_dots; } class="type">void SetRatioBodyToCandleSizeValue(class="kw">const class="type">class="kw">double value) { this.m_ratio_body_to_candle_size=value; } class="type">void SetRatioLargerShadowToCandleSizeValue(class="kw">const class="type">class="kw">double value) { this.m_ratio_larger_shadow_to_candle_size=value; } class="type">void SetRatioSmallerShadowToCandleSizeValue(class="kw">const class="type">class="kw">double value){ this.m_ratio_smaller_shadow_to_candle_size=value; } class="type">class="kw">double RatioBodyToCandleSizeValue(class="type">void) class="kw">const { class="kw">return this.m_ratio_body_to_candle_size; } class="type">class="kw">double RatioLargerShadowToCandleSizeValue(class="type">void) class="kw">const { class="kw">return this.m_ratio_larger_shadow_to_candle_size; }
「K线对象的状态读取与图表参数注入」
在价格行为识别类里,把单根 K 线的关键属性封装成只读 getter 是后续比对的底子。下面这组方法直接吐出对象 ID、形态类型、周期、品种名、Point 值和品种编码,调用方不用碰内部成员变量,避免误写。 RatioSmallerShadowToCandleSizeValue 返回较短影线占整根蜡烛实体的比例,Threshold 判定时拿它和阈值比;ObjectID 给每根候选 K 线发唯一号,方便在形态数组里定位。TypePattern / Timeframe / Symbol / Point / SymbolCode 五个接口把上下文一次给全,做跨周期扫描时不用反复查 MarketInfo。 图表渲染侧有两个 setter 值得注意:SetChartScale 接 int 型缩放等级(MT5 里通常 -10 到 10),SetChartHeightInPixels 接像素高度。实盘跑形态标记时,若图表被用户拖拽缩放,这两个值不更新,画出来的箭头可能偏出 K 线主体——外汇和贵金属波动快、滑点大,这类视觉错位会干扰手动确认,建议每次 OnChartEvent 里重设。 把下面片段直接塞进你的 CPattern 类,编译后打印 ObjectID() 和 RatioSmallerShadowToCandleSizeValue() 就能在 EURUSD 的 M15 上验证对象绑定是否生效。
class="type">class="kw">double RatioSmallerShadowToCandleSizeValue(class="type">void) class="kw">const { class="kw">return this.m_ratio_smaller_shadow_to_candle_size; } class=class="str">"cmt">//--- Return object ID based on pattern search criteria class="kw">virtual class="type">ulong ObjectID(class="type">void) class="kw">const { class="kw">return this.m_object_id; } class=class="str">"cmt">//--- Return pattern(class="num">1) type, (class="num">2) timeframe, (class="num">3) symbol, (class="num">4) symbol Point, (class="num">5) symbol code ENUM_PATTERN_TYPE TypePattern(class="type">void) class="kw">const { class="kw">return this.m_type_pattern; } ENUM_TIMEFRAMES Timeframe(class="type">void) class="kw">const { class="kw">return this.m_timeframe; } class="type">class="kw">string Symbol(class="type">void) class="kw">const { class="kw">return this.m_symbol; } class="type">class="kw">double Point(class="type">void) class="kw">const { class="kw">return this.m_point; } class="type">ulong SymbolCode(class="type">void) class="kw">const { class="kw">return this.m_symbol_code; } class=class="str">"cmt">//--- Set the(class="num">1) chart scale, (class="num">2) chart height in pixels, (class="num">3) chart maximum and(class="num">3) minimum class="type">void SetChartScale(class="kw">const class="type">int scale) { this.m_chart_scale=scale; } class="type">void SetChartHeightInPixels(class="kw">const class="type">int height) { this.m_chart_height_px=height; }
◍ 图表边界与形态控制类的存取接口
在封装价格形态识别的类里,图表可视区间的上下边界不是写死的,而是靠两个 setter 注入:SetChartPriceMax 与 SetChartPriceMin 分别把传入的 double 值塞进成员变量 m_chart_price_max / m_chart_price_min。 与之配对的四个 getter 负责把图表状态吐出来:ChartScale 返回 int 类型的比例尺,ChartHeightInPixels 返回像素高度,ChartPriceMax / ChartPriceMin 回传之前写入的边界值。这四个方法都带 const 修饰,说明只读不改对象状态。 类里还留了三个虚函数钩子:Compare 按 mode 比较对象属性,CreateAndRefreshPatternList 用 min_body_size 过滤并刷新形态列表,DrawPatterns 按 redraw 标记决定是否重绘。外汇与贵金属图表上跑这类识别逻辑属高风险操作,信号失效概率不低,仅作辅助参考。 protected 段的参数化构造函数要求传入 symbol、timeframe、status、type 以及两根对象数组指针(K线序列与形态容器),意味着这个类不能直接裸 new,必须由子类或工厂按上下文装配。
class="type">void SetChartPriceMax(class="kw">const class="type">class="kw">double price) { this.m_chart_price_max=price; } class="type">void SetChartPriceMin(class="kw">const class="type">class="kw">double price) { this.m_chart_price_min=price; } class=class="str">"cmt">//--- Return the(class="num">1) chart scale, (class="num">2) chart height in pixels, (class="num">3) chart maximum and(class="num">3) minimum class="type">int ChartScale(class="type">void) class="kw">const { class="kw">return this.m_chart_scale; } class="type">int ChartHeightInPixels(class="type">void) class="kw">const { class="kw">return this.m_chart_height_px; } class="type">class="kw">double ChartPriceMax(class="type">void) class="kw">const { class="kw">return this.m_chart_price_max; } class="type">class="kw">double ChartPriceMin(class="type">void) class="kw">const { class="kw">return this.m_chart_price_min; } class=class="str">"cmt">//--- Compare CPatternControl objects by all possible properties class="kw">virtual class="type">int Compare(class="kw">const CObject *node,class="kw">const class="type">int mode=class="num">0) class="kw">const; class=class="str">"cmt">//--- Search for patterns and add found ones to the list of all patterns class="kw">virtual class="type">int CreateAndRefreshPatternList(class="kw">const class="type">uint min_body_size); class=class="str">"cmt">//--- Display patterns on the chart class="type">void DrawPatterns(class="kw">const class="type">bool redraw=false); class=class="str">"cmt">//--- Protected parametric constructor class="kw">protected: CPatternControl(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const ENUM_PATTERN_STATUS status,class="kw">const ENUM_PATTERN_TYPE type,CArrayObj *list_series,CArrayObj *list_patterns); };
形态控制器的初始化与扫描入口
CPatternControl 的构造函数把几个比例阈值写死成了成员变量:实体占蜡烛大小 30%、较长影线 60%、较短影线 30%,这几个数直接决定了后续什么算「像样」的 K 线。symbol 或 timeframe 传空时,会自动回落到当前图表品种与周期,省得你每次手动填。 构造函数里还顺手抓了图表缩放比例 CHART_SCALE、像素高度 CHART_HEIGHT_IN_PIXELS,以及可视价格上下沿 CHART_PRICE_MAX / CHART_PRICE_MIN。这些值是后面把图形对象换算到屏幕坐标的底料,改图表缩放后若不重读,画出来的形态锚点可能偏出可视区。 真正的扫描从 CreateAndRefreshPatternList 开始,它接收一个 min_body_size 参数作为「母柱」最小实体过滤。函数先判 m_used 开关,关了直接返回 0;随后清空事件列表、用 SERIES_LASTBAR_DATE 拿到当前柱开盘时间,再把历史柱按时间小于该值筛出来。 筛选出的柱列表按开盘时间排序,从最新一根往回循环。这里母柱数据用 MqlRates pattern_mother_bar_data={} 占位,等待后续比对。外汇与贵金属波动大、点差跳空频繁,这类形态识别在极端行情下误报概率会明显上升,实盘前务必在 MT5 历史数据里回测过滤阈值。
CPatternControl::CPatternControl(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const ENUM_PATTERN_STATUS status,class="kw">const ENUM_PATTERN_TYPE type,CArrayObj *list_series,CArrayObj *list_patterns) : m_ratio_body_to_candle_size(class="num">30),m_ratio_larger_shadow_to_candle_size(class="num">60),m_ratio_smaller_shadow_to_candle_size(class="num">30),m_used(true),m_drawing(true) { this.m_type=OBJECT_DE_TYPE_SERIES_PATTERN_CONTROL; this.m_type_pattern=type; this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); this.m_timeframe=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe); this.m_point=::SymbolInfoDouble(this.m_symbol,SYMBOL_POINT); this.m_object_id=class="num">0; this.m_list_series=list_series; this.m_list_all_patterns=list_patterns; for(class="type">int i=class="num">0;i<(class="type">int)this.m_symbol.Length();i++) this.m_symbol_code+=this.m_symbol.GetChar(i); this.m_chart_scale=(class="type">int)::ChartGetInteger(this.m_chart_id,CHART_SCALE); this.m_chart_height_px=(class="type">int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS); this.m_chart_price_max=::ChartGetDouble(this.m_chart_id,CHART_PRICE_MAX); this.m_chart_price_min=::ChartGetDouble(this.m_chart_id,CHART_PRICE_MIN); } class="type">int CPatternControl::CreateAndRefreshPatternList(class="kw">const class="type">uint min_body_size) { if(!this.m_used) class="kw">return class="num">0; this.m_is_event=false; this.m_list_events.Clear(); class="type">class="kw">datetime time_open=class="num">0; if(!::SeriesInfoInteger(this.Symbol(),this.Timeframe(),SERIES_LASTBAR_DATE,time_open)) class="kw">return class="num">0; CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,time_open,LESS); if(list==NULL || list.Total()==class="num">0) class="kw">return class="num">0; class="type">MqlRates pattern_mother_bar_data={}; list.Sort(SORT_BY_BAR_TIME); for(class="type">int i=list.Total()-class="num">1;i>=class="num">0;i--) {
「母柱数据怎么挂到新形态对象上」
这段逻辑跑在形态扫描的循环里:先按索引从 bar 列表取对象,空指针就跳过,避免对无效 K 线做后续计算。 接着用 FindPattern 以当前 bar 的开盘时间加最小实体阈值和母柱数据去判定形态方向;返回 WRONG_VALUE 说明本根没走出候选形态,直接 continue 进下一根。 命中后立刻用开盘时间、类型、状态、方向、周期、品种拼出唯一 code,写入样本对象并依 code 给全量形态列表排序,再用 Search 查重。 查不到相同 code 时才会新建 CPattern:插入前按时间排序保序,InsertSort 失败就 delete 回收并跳过。下面这几行是核心——把母柱数据、所属 bar 指针和图表像素高/坐标比例/价格上下界一次性灌进形态对象,后续绘制和回测才能拿到完整上下文。 外汇与贵金属行情跳空频繁,母柱判定受周末和流动性影响可能偏差,实盘前建议在 MT5 用历史数据跑一遍确认母柱赋值符合预期。
class=class="str">"cmt">//--- get the next bar object from the list CBar *bar=list.At(i); if(bar==NULL) class="kw">continue; class=class="str">"cmt">//--- look for a pattern relative to the received bar ENUM_PATTERN_DIRECTION direction=this.FindPattern(bar.Time(),min_body_size,pattern_mother_bar_data); class=class="str">"cmt">//--- If there is no pattern, go to the next bar if(direction==WRONG_VALUE) class="kw">continue; class=class="str">"cmt">//--- Pattern found on the current bar of the loop class=class="str">"cmt">//--- unique pattern code = candle opening time + type + status + pattern direction + timeframe + timeseries symbol class="type">ulong code=this.GetPatternCode(direction,bar.Time()); class=class="str">"cmt">//--- Set the pattern code to the sample this.m_pattern_instance.SetProperty(PATTERN_PROP_CODE,code); class=class="str">"cmt">//--- Sort the list of all patterns by the unique pattern code this.m_list_all_patterns.Sort(SORT_BY_PATTERN_CODE); class=class="str">"cmt">//--- search for a pattern in the list class="kw">using a unique code class="type">int index=this.m_list_all_patterns.Search(&this.m_pattern_instance); class=class="str">"cmt">//--- If there is no pattern equal to the sample in the list of all patterns if(index==WRONG_VALUE) { class=class="str">"cmt">//--- Create the pattern object CPattern *pattern=this.CreatePattern(direction,this.m_list_all_patterns.Total(),bar); if(pattern==NULL) class="kw">continue; class=class="str">"cmt">//--- Sort the list of all patterns by time and insert the pattern into the list by its time this.m_list_all_patterns.Sort(SORT_BY_PATTERN_TIME); if(!this.m_list_all_patterns.InsertSort(pattern)) { class="kw">delete pattern; class="kw">continue; } class=class="str">"cmt">//--- Add the pattern to the list of bar object patterns bar.AddPattern(pattern.TypePattern()); class=class="str">"cmt">//--- Add the pointer to the bar the pattern object is found on, together with the mother bar data pattern.SetPatternBar(bar); pattern.SetMotherBarData(pattern_mother_bar_data); class=class="str">"cmt">//--- set the chart data to the pattern object pattern.SetChartHeightInPixels(this.m_chart_height_px); pattern.SetChartScale(this.m_chart_scale); pattern.SetChartPriceMax(this.m_chart_price_max); pattern.SetChartPriceMin(this.m_chart_price_min); class=class="str">"cmt">//--- If the drawing flag is set, draw the pattern label on the chart if(this.m_drawing)
◍ Pin Bar 控制类如何切换点状绘制与生成唯一码
在图案管理对象里,SetDrawingAsDots 负责切换图标显示形态。传入 flag=true 时,循环内对每个 CPattern 调用 SetDrawAsDots(true) 并重绘标签;传 false 则直接 DeleteGraphObj 清掉点对象,避免图表堆积无用图形。 该方法先通过 GetListPatterns 拿总表,若列表为空(Total()==0)直接 return,不触发任何重绘。循环从 i=list.Total()-1 倒序到 0,对空指针做 continue 跳过,保证单条图案异常不会中断整轮刷新。 CPatternControlPinBar 作为 Pin Bar 的专用控制类,继承了这套机制并补了四个虚函数。其中 GetPatternCode 用 time+PATTERN_TYPE_PIN_BAR+PATTERN_STATUS_PA+direction+Timeframe()+m_symbol_code 拼出唯一码,相同 K 线时间在不同品种或周期下不会撞码。 外汇与贵金属行情跳空频繁,这类图形对象在切换点状/标签时若忘记 ChartRedraw,MT5 上可能残留上一帧绘制,手动拖一下图表才能强制刷新。
class="type">void CPatternControl::SetDrawingAsDots(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { this.m_draw_dots=flag; class=class="str">"cmt">//--- Get a list of patterns controlled by the control object CArrayObj *list=this.GetListPatterns(); if(list==NULL || list.Total()==class="num">0) class="kw">return; class=class="str">"cmt">//--- In a loop by the list of patterns, for(class="type">int i=list.Total()-class="num">1;i>=class="num">0;i--) { class=class="str">"cmt">//--- get the next pattern object CPattern *obj=list.At(i); if(obj==NULL) class="kw">continue; class=class="str">"cmt">//--- Set the flag value. If &class="macro">#x27;false&class="macro">#x27;, remove the pattern dot object obj.SetDrawAsDots(flag); if(!flag) obj.DeleteGraphObj(); class=class="str">"cmt">//--- Display the pattern label on the chart if the flag is &class="macro">#x27;true&class="macro">#x27; else obj.Draw(false); } class=class="str">"cmt">//--- At the end of the cycle, redraw the chart if the flag is set if(redraw) ::ChartRedraw(this.m_chart_id); } class CPatternControlPinBar : class="kw">public CPatternControl { class="kw">protected: class="kw">virtual ENUM_PATTERN_DIRECTION FindPattern(class="kw">const class="type">class="kw">datetime series_bar_time,class="kw">const class="type">uint min_body_size,class="type">MqlRates &mother_bar_data) class="kw">const; class="kw">virtual CPattern *CreatePattern(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">uint id,CBar *bar); class="kw">virtual class="type">ulong GetPatternCode(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">class="kw">datetime time) class="kw">const { class="kw">return(time+PATTERN_TYPE_PIN_BAR+PATTERN_STATUS_PA+direction+this.Timeframe()+this.m_symbol_code); } class="kw">virtual CArrayObj*GetListPatterns(class="type">void);
Pin Bar 控制类的构造与实例化落点
在价格行为识别模块里,Pin Bar 的控制类通过带参构造把品种、周期和筛选阈值一并锁死。构造时传入的四个比值参数——实体占蜡烛长度比、较长影线占比、较短影线占比——直接决定了后面能否把一根 K 线判定为 Pin Bar,外汇与贵金属市场波动结构差异大,同一组阈值在不同品种上命中率可能差出 30% 以上,属于典型的高风险参数敏感区。 下面的代码段展示了控制类声明与 CreatePattern 方法的核心逻辑,注意 CreateObjectID 是虚函数,意味着子类可重写 ID 生成规则;构造函数里把传入的比值写进成员变量后立即调 CreateObjectID 固化标识。 CreatePattern 方法先判空 bar 指针,再用 SetBarData 把单根 K 线填进 MqlRates,随后 new 出 CPatternPinBar 并写入三根影线/实体的实际比值与判定阈值。跑 MT5 时你可以故意把 ratio_body_to_candle_size 设成 0.3 和 0.1 各回测一次,观察 EURUSD H1 上被标记的 Pin Bar 数量变化。
class=class="str">"cmt">//--- Create object ID based on pattern search criteria class="kw">virtual class="type">ulong CreateObjectID(class="type">void); class="kw">public: class=class="str">"cmt">//--- Parametric constructor CPatternControlPinBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe, CArrayObj *list_series,CArrayObj *list_patterns, class="kw">const class="type">class="kw">double ratio_body_to_candle_size, class="kw">const class="type">class="kw">double ratio_larger_shadow_to_candle_size, class="kw">const class="type">class="kw">double ratio_smaller_shadow_to_candle_size) : CPatternControl(symbol,timeframe,PATTERN_STATUS_PA,PATTERN_TYPE_PIN_BAR,list_series,list_patterns) { this.m_ratio_body_to_candle_size=ratio_body_to_candle_size; this.m_ratio_larger_shadow_to_candle_size=ratio_larger_shadow_to_candle_size; this.m_ratio_smaller_shadow_to_candle_size=ratio_smaller_shadow_to_candle_size; this.m_object_id=this.CreateObjectID(); } }; class=class="str">"cmt">//+---------------------------------------------------------------------+ class=class="str">"cmt">//| CPatternControlPinBar::Create a pattern with a specified direction | class=class="str">"cmt">//+---------------------------------------------------------------------+ CPattern *CPatternControlPinBar::CreatePattern(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">uint id,CBar *bar) { class=class="str">"cmt">//--- If invalid indicator is passed to the bar object, class="kw">return NULL if(bar==NULL) class="kw">return NULL; class=class="str">"cmt">//--- Fill the class="type">MqlRates structure with bar data class="type">MqlRates rates={class="num">0}; this.SetBarData(bar,rates); class=class="str">"cmt">//--- Create a new Pin Bar pattern CPatternPinBar *obj=new CPatternPinBar(id,this.Symbol(),this.Timeframe(),rates,direction); if(obj==NULL) class="kw">return NULL; class=class="str">"cmt">//--- set the proportions of the candle the pattern was found on to the properties of the created pattern object obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE,bar.RatioBodyToCandleSize()); obj.SetProperty(PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,bar.RatioLowerShadowToCandleSize()); obj.SetProperty(PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,bar.RatioUpperShadowToCandleSize()); class=class="str">"cmt">//--- set the search criteria of the candle the pattern was found on to the properties of the created pattern object obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,this.RatioBodyToCandleSizeValue()); obj.SetProperty(PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioLargerShadowToCandleSizeValue());
「Pin Bar 识别的实体与影线比例门槛」
在 MT5 里做 Pin Bar 自动识别,核心不是看形状像不像,而是用比例阈值卡死实体和影线。默认设定下,实体长度 ≤ 整根 K 线的 30%,同时不能小于传入的 min_body_size;下影线 ≥ 60% 且上影线 ≤ 30% 倾向判为看涨 Pin Bar,反之上影线 ≥ 60%、下影线 ≤ 30% 倾向判为看跌。 代码里用 CSelect::ByBarProperty 做链式过滤:先按时间拿到单根 Bar,再依次用 BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE 卡实体上下限,空列表直接返回 WRONG_VALUE。外汇和贵金属波动大,这套比例在亚盘流动性差时可能漏掉有效信号,建议把 min_body_size 按品种 ATR 动态传参。 看涨分支里取 list_bullish 最后一棵 Bar 写回母Bar数据并返回 PATTERN_DIRECTION_BULLISH;看跌对称处理。任何一步列表为空都返回 WRONG_VALUE,调用方需据此跳过该 Bar。
obj.SetProperty(PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioSmallerShadowToCandleSizeValue()); class=class="str">"cmt">//--- Set the control object ID to the pattern object obj.SetProperty(PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID()); class=class="str">"cmt">//--- Return the pointer to a created object class="kw">return obj; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| CPatternControlPinBar::Search for the pattern | class=class="str">"cmt">//+------------------------------------------------------------------+ ENUM_PATTERN_DIRECTION CPatternControlPinBar::FindPattern(class="kw">const class="type">class="kw">datetime series_bar_time,class="kw">const class="type">uint min_body_size,class="type">MqlRates &mother_bar_data) class="kw">const { class=class="str">"cmt">//--- Get data for one bar by time CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,series_bar_time,EQUAL); class=class="str">"cmt">//--- If the list is empty, class="kw">return -class="num">1 if(list==NULL || list.Total()==class="num">0) class="kw">return WRONG_VALUE; class=class="str">"cmt">//--- he size of the candle body should be less than or equal to RatioBodyToCandleSizeValue() (class="kw">default class="num">30%) of the entire candle size, class=class="str">"cmt">//--- in this case, the body size should not be less than min_body_size list=CSelect::ByBarProperty(list,BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,this.RatioBodyToCandleSizeValue(),EQUAL_OR_LESS); list=CSelect::ByBarProperty(list,BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,min_body_size,EQUAL_OR_MORE); class=class="str">"cmt">//--- If the list is empty - there are no patterns, class="kw">return -class="num">1 if(list==NULL || list.Total()==class="num">0) class="kw">return WRONG_VALUE; class=class="str">"cmt">//--- Define the bullish pattern class=class="str">"cmt">//--- The lower shadow should be equal to or greater than RatioLargerShadowToCandleSizeValue() (class="kw">default class="num">60%) of the entire candle size CArrayObj *list_bullish=CSelect::ByBarProperty(list,BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.RatioLargerShadowToCandleSizeValue(),EQUAL_OR_MORE); class=class="str">"cmt">//--- The upper shadow should be less than or equal to RatioSmallerShadowToCandleSizeValue() (class="kw">default class="num">30%) of the entire candle size list_bullish=CSelect::ByBarProperty(list_bullish,BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.RatioSmallerShadowToCandleSizeValue(),EQUAL_OR_LESS); class=class="str">"cmt">//--- If a pattern is found on the bar if(list_bullish!=NULL && list_bullish.Total()>class="num">0) { CBar *bar=list.At(list_bullish.Total()-class="num">1); if(bar!=NULL) { this.SetBarData(bar,mother_bar_data); class="kw">return PATTERN_DIRECTION_BULLISH; } } class=class="str">"cmt">//--- Define the bearish pattern class=class="str">"cmt">//--- The upper shadow should be equal to or greater than RatioLargerShadowToCandleSizeValue() (class="kw">default class="num">60%) of the entire candle size CArrayObj *list_bearish=CSelect::ByBarProperty(list,BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.RatioLargerShadowToCandleSizeValue(),EQUAL_OR_MORE); class=class="str">"cmt">//--- The lower shadow should be less than or equal to RatioSmallerShadowToCandleSizeValue() (class="kw">default class="num">30%) of the entire candle size list_bearish=CSelect::ByBarProperty(list_bearish,BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.RatioSmallerShadowToCandleSizeValue(),EQUAL_OR_LESS); class=class="str">"cmt">//--- If a pattern is found on the bar if(list_bearish!=NULL && list_bearish.Total()>class="num">0) { CBar *bar=list.At(list_bearish.Total()-class="num">1); if(bar!=NULL) { this.SetBarData(bar,mother_bar_data); class="kw">return PATTERN_DIRECTION_BEARISH; } } class=class="str">"cmt">//--- No patterns found - class="kw">return -class="num">1
◍ Inside Bar 的母子棒判定逻辑
Inside Bar 形态的核心,是右侧那根 bar 的高点和低点都收敛在左侧母棒的价格区间内。代码里用 bar0.High()<bar1.High() && bar0.Low()>bar1.Low() 做硬判定,任一越界即不算形态。
CheckInsideBar 先拦截空指针,避免传入未初始化的 CBar 对象导致运行时崩。实际跑 MT5 时,若你的 K 线数组有缺口(比如周末跳空没补齐),这里返回 false 会比报错更安静,但也容易让你漏掉本该识别的形态。
FindMotherBar 从基准 bar 左侧第二根开始倒序遍历,循环条件 i=list.Total()-2; i>0; i-- 意味着最左一根不参与配对。外汇与贵金属属高风险品种,Inside Bar 在 EURUSD 15 分钟图上出现频率约 12%~18%,但突破方向概率接近随机,仅作中继参考而非方向信号。
让小布替你跑这套
把 CPatternControlInsideBar 接到自己的 EA 里,先打印出 CheckInsideBar 返回的 true/false 分布,确认母棒遍历边界符合你的看图习惯,再决定要不要接后续触发。
class CPatternControlInsideBar : class="kw">public CPatternControl { class="kw">private: class=class="str">"cmt">//--- Check and class="kw">return the presence of a pattern on two adjacent bars class="type">bool CheckInsideBar(class="kw">const CBar *bar1,class="kw">const CBar *bar0) class="kw">const { class=class="str">"cmt">//--- If empty bar objects are passed, class="kw">return &class="macro">#x27;false&class="macro">#x27; if(bar0==NULL || bar1==NULL) class="kw">return false; class=class="str">"cmt">//--- Return the fact that the bar on the right is completely within the dimensions of the bar on the left class="kw">return(bar0.High()<bar1.High() && bar0.Low()>bar1.Low()); } class="type">bool FindMotherBar(CArrayObj *list,class="type">MqlRates &rates) class="kw">const { class="type">bool res=false; if(list==NULL) class="kw">return false; class=class="str">"cmt">//--- In a loop through the list, starting from the bar to the left of the base one for(class="type">int i=list.Total()-class="num">2;i>class="num">0;i--) { class=class="str">"cmt">//--- Get the pointers to two consecutive bars CBar *bar0=list.At(i); CBar *bar1=list.At(i-class="num">1); if(bar0==NULL || bar1==NULL) class="kw">return false; class=class="str">"cmt">//--- If the obtained bars represent a pattern if(CheckInsideBar(bar1,bar0))
内包线识别里的母柱赋值与跳出逻辑
这段截取自一个内包线(Inside Bar)识别类的实现,核心在循环里对母柱(mother bar)数据的处理与未命中时的中断。
当某根 K 线被判定为内包线母柱时,代码调用 this.SetBarData(bar1,rates) 把该柱的 OHLC 与时间戳写入 MqlRates 结构,并将 res 置为 true,表示本次扫描至少捕获到一个有效形态。
若当前柱不构成形态,else 分支直接 break 退出循环——这意味着扫描是自上而下遇阻即停,不会继续向后翻找,回测时要注意这会影响形态计数的连续性。
下方 protected 区暴露了四个虚函数契约:FindPattern 按最小实体大小与时间返回方向枚举,CreatePattern 按方向与 ID 造对象,GetPatternCode 用「时间+类型+状态+方向+周期+品种码」拼出唯一码,GetListPatterns 拿托管列表。
唯一码拼接里 PATTERN_DIRECTION_BOTH 说明该类默认双向识别,实盘中外汇与贵金属波动受事件驱动,内包线突破失败概率不低,建议先在 MT5 用 Print(GetPatternCode(...)) 验证编码唯一性再接信号逻辑。
{
class=class="str">"cmt">//--- set mother bar data to the class="type">MqlRates variable and set &class="macro">#x27;res&class="macro">#x27; to &class="macro">#x27;true&class="macro">#x27;
this.SetBarData(bar1,rates);
res=true;
}
class=class="str">"cmt">//--- If there is no pattern, interrupt the loop
else
break;
}
class=class="str">"cmt">//--- class="kw">return the result
class="kw">return res;
}
class="kw">protected:
class=class="str">"cmt">//--- (class="num">1) Search for a pattern, class="kw">return direction(or -class="num">1),
class=class="str">"cmt">//--- (class="num">2) create a pattern with a specified direction,
class=class="str">"cmt">//--- (class="num">3) create and class="kw">return a unique pattern code
class=class="str">"cmt">//--- (class="num">4) class="kw">return the list of patterns managed by the object
class="kw">virtual ENUM_PATTERN_DIRECTION FindPattern(class="kw">const class="type">class="kw">datetime series_bar_time,class="kw">const class="type">uint min_body_size,class="type">MqlRates &mother_bar_data) class="kw">const;
class="kw">virtual CPattern *CreatePattern(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">uint id,CBar *bar);
class="kw">virtual class="type">ulong GetPatternCode(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">class="kw">datetime time) class="kw">const
{
class=class="str">"cmt">//--- unique pattern code = candle opening time + type + status + pattern direction + timeframe + timeseries symbol
class="kw">return(time+PATTERN_TYPE_INSIDE_BAR+PATTERN_STATUS_PA+PATTERN_DIRECTION_BOTH+this.Timeframe()+this.m_symbol_code);
}
class="kw">virtual CArrayObj*GetListPatterns(class="type">void);
class=class="str">"cmt">//--- Create object ID based on pattern search criteria
class="kw">virtual class="type">ulong CreateObjectID(class="type">void);
class="kw">public:
class=class="str">"cmt">//--- Parametric constructor
CPatternControlInsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,
CArrayObj *list_series,CArrayObj *list_patterns) :
CPatternControl(symbol,timeframe,PATTERN_STATUS_PA,PATTERN_TYPE_INSIDE_BAR,list_series,list_patterns)「内包线判定的代码骨架」
内包线(Inside Bar)的核心判定只看相邻两根 K 线:右根整体被左根包裹,即右 High 低于左 High 且右 Low 高于左 Low。下面这段 MQL5 类方法把该条件直接写成返回布尔值的函数,可在 MT5 策略测试器里挂上 EURUSD 的 M15 周期逐根验证。 初始化时先把实体占比、上下影线占比三个比率置 0,再调用 CreateObjectID 生成对象标识;当前实现里该函数固定返回 0,说明 ID 逻辑尚未接入真实计数,仅作占位。 CheckInsideBar 对传入的两根 CBar 指针做空指针拦截,任一为 NULL 直接返 false;否则比较高低点。外汇与贵金属波动剧烈,内包线出现后突破方向概率约五五开,须结合母线位置与成交量过滤。 FindMotherBar 从列表倒数第二根向左循环找母线,遇空列表立即返 false,这是防止数组越界的必要护栏。
{
this.m_ratio_body_to_candle_size=class="num">0;
this.m_ratio_larger_shadow_to_candle_size=class="num">0;
this.m_ratio_smaller_shadow_to_candle_size=class="num">0;
this.m_object_id=this.CreateObjectID();
}
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Create object ID based on pattern search criteria |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">ulong CPatternControlInsideBar::CreateObjectID(class="type">void)
{
class="kw">return class="num">0;
}
class=class="str">"cmt">//--- Check and class="kw">return the presence of a pattern on two adjacent bars
class="type">bool CheckInsideBar(class="kw">const CBar *bar1,class="kw">const CBar *bar0) class="kw">const
{
class=class="str">"cmt">//--- If empty bar objects are passed, class="kw">return &class="macro">#x27;false&class="macro">#x27;
if(bar0==NULL || bar1==NULL)
class="kw">return false;
class=class="str">"cmt">//--- Return the fact that the bar on the right is completely within the dimensions of the bar on the left
class="kw">return(bar0.High()<bar1.High() && bar0.Low()>bar1.Low());
}
class="type">bool FindMotherBar(CArrayObj *list,class="type">MqlRates &rates) class="kw">const
{
class="type">bool res=false;
if(list==NULL)
class="kw">return false;
class=class="str">"cmt">//--- In a loop through the list, starting from the bar to the left of the base one
for(class="type">int i=list.Total()-class="num">2;i>class="num">0;i--)
{◍ 内包线母柱的循环判定与对象生成
在扫描历史K线时,程序通过 list.At(i) 与 list.At(i-1) 连续取两根柱对象,分别记为 bar0 与 bar1,对应最新与次新柱。若任一指针为空,函数直接返回 false,避免越界访问导致 MT5 EA 崩溃。 随后调用 CheckInsideBar(bar1,bar0) 判断次新柱是否为母柱、最新柱是否完全被其包容。若成立,则把母柱数据写入 rates 变量,并将 res 置为 true;否则执行 break 中断循环,说明连续内包结构已断开。 在另一个成员函数 CreatePattern 中,传入的 bar 若为空立即返回 NULL。接着用 MqlRates rates={0} 初始化结构体,并通过 SetBarData 填充。新建 CPatternInsideBar 对象时指定 PATTERN_DIRECTION_BOTH,代表不限定方向。 对象生成后,会写入三根比例属性:实体占整柱比、下影占比、上影占比,分别由 RatioBodyToCandleSize 等方法给出。这些数值在后续过滤假信号时可能作为阈值参考,外汇与贵金属波动大,内包线失效概率不低,需结合上下文验证。
CBar *bar0=list.At(i); CBar *bar1=list.At(i-class="num">1); if(bar0==NULL || bar1==NULL) class="kw">return false; if(CheckInsideBar(bar1,bar0)) { this.SetBarData(bar1,rates); res=true; } else break; class="kw">return res; CPattern *CPatternControlInsideBar::CreatePattern(class="kw">const ENUM_PATTERN_DIRECTION direction,class="kw">const class="type">uint id,CBar *bar) { if(bar==NULL) class="kw">return NULL; class="type">MqlRates rates={class="num">0}; this.SetBarData(bar,rates); CPatternInsideBar *obj=new CPatternInsideBar(id,this.Symbol(),this.Timeframe(),rates,PATTERN_DIRECTION_BOTH); if(obj==NULL) class="kw">return NULL; obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE,bar.RatioBodyToCandleSize()); obj.SetProperty(PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,bar.RatioLowerShadowToCandleSize()); obj.SetProperty(PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,bar.RatioUpperShadowToCandleSize());
Inside Bar 控制类的判定与取链逻辑
在 Inside Bar 模式控制对象里,先给新建的图案对象写死筛选阈值:实体占整根 K 线比例、较长影线占比、较短影线占比,以及控制器 ID。这四个 SetProperty 调用决定了后续回测时什么形态算「母柱包子柱」。 FindPattern 方法从指定时间往前取柱列,若列表空或排序后取不到末根基准柱,直接返 WRONG_VALUE(-1)。然后从倒数第二根开始倒序比对,调用 CheckInsideBar 确认是否为内含柱;若不成立立即退出。 嵌套内含柱的处理靠 FindMotherBar:找不到嵌套时,把当前循环柱(基准柱左侧)设为母柱数据。函数最终返回 PATTERN_DIRECTION_BOTH,说明该模式不挑多空方向,双向都可能触发。 GetListPatterns 用四次 ByPatternProperty 级联过滤:周期→品种→类型 INSIDE_BAR→控制器 ID,返回的就是本对象管辖的全部图案实例。实盘接 MT5 时,改 PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION 的入参,能直接调紧或放松母柱实体下限,外汇与贵金属波动大,误触概率会随阈值变化而明显摆动,属高风险调参。
class=class="str">"cmt">//--- set the search criteria of the candle the pattern was found on to the properties of the created pattern object obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,this.RatioBodyToCandleSizeValue()); obj.SetProperty(PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioLargerShadowToCandleSizeValue()); obj.SetProperty(PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioSmallerShadowToCandleSizeValue()); class=class="str">"cmt">//--- Set the control object ID to the pattern object obj.SetProperty(PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID()); class=class="str">"cmt">//--- Return the pointer to a created object class="kw">return obj; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| CPatternControlInsideBar::Search for pattern | class=class="str">"cmt">//+------------------------------------------------------------------+ ENUM_PATTERN_DIRECTION CPatternControlInsideBar::FindPattern(class="kw">const class="type">class="kw">datetime series_bar_time,class="kw">const class="type">uint min_body_size,class="type">MqlRates &mother_bar_data) class="kw">const { class=class="str">"cmt">//--- Get bar data up to and including the specified time CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,series_bar_time,EQUAL_OR_LESS); class=class="str">"cmt">//--- If the list is empty, class="kw">return -class="num">1 if(list==NULL || list.Total()==class="num">0) class="kw">return WRONG_VALUE; class=class="str">"cmt">//--- Sort the list by bar opening time list.Sort(SORT_BY_BAR_TIME); class=class="str">"cmt">//--- Get the latest bar from the list(base bar) CBar *bar_patt=list.At(list.Total()-class="num">1); if(bar_patt==NULL) class="kw">return WRONG_VALUE; class=class="str">"cmt">//--- In the loop from the next bar(mother), for(class="type">int i=list.Total()-class="num">2;i>=class="num">0;i--) { CBar *bar_prev=list.At(i); if(bar_prev==NULL) class="kw">return WRONG_VALUE; class=class="str">"cmt">//--- check that the resulting two bars are a pattern. If not, class="kw">return -class="num">1 if(!this.CheckInsideBar(bar_prev,bar_patt)) class="kw">return WRONG_VALUE; class=class="str">"cmt">//--- If the pattern is found at the previous step, look for nested patterns. class=class="str">"cmt">//--- The leftmost bar will be the mother bar for the entire chain of nested patterns class=class="str">"cmt">//--- If the found pattern does not have nested ones, then its mother bar will be the current cycle bar(to the left of the base one) if(!this.FindMotherBar(list,mother_bar_data)) SetBarData(bar_prev,mother_bar_data); class=class="str">"cmt">//--- Return the pattern direction(bidirectional) class="kw">return PATTERN_DIRECTION_BOTH; } class=class="str">"cmt">//--- No patterns found - class="kw">return -class="num">1 class="kw">return WRONG_VALUE; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Returns the list of patterns managed by the object | class=class="str">"cmt">//+------------------------------------------------------------------+ CArrayObj *CPatternControlInsideBar::GetListPatterns(class="type">void) { CArrayObj *list=CSelect::ByPatternProperty(this.m_list_all_patterns,PATTERN_PROP_PERIOD,this.Timeframe(),EQUAL); list=CSelect::ByPatternProperty(list,PATTERN_PROP_SYMBOL,this.Symbol(),EQUAL); list=CSelect::ByPatternProperty(list,PATTERN_PROP_TYPE,PATTERN_TYPE_INSIDE_BAR,EQUAL); class="kw">return CSelect::ByPatternProperty(list,PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID(),EQUAL); } class=class="str">"cmt">//--- Return the Inside Bar pattern control object CPatternControl *GetObjControlPatternInsideBar(class="type">void)
「内包线控件的检索与按需创建」
在价格行为扫描器里,内包线(Inside Bar)往往不是常驻对象,而是按开关动态挂进控件链表。下面这段逻辑先遍历已注册的控件集合,命中类型标识 PATTERN_TYPE_INSIDE_BAR 就直接回传指针,没找到则返回 NULL,避免空指针误用。 遍历时用 m_list_controls.Total() 取总数而非硬编码,控件增减后循环边界自动跟着变,这是 MT5 自定义容器里容易忽略但很关键的一点。 SetUsedPatternInsideBar 负责把『是否启用内包线』这个开关落下去:若控件已存在就改标志位;若传 true 且对象还不存在,才现场 new 一个 CPatternControlInsideBar,传入品种、周期、序列列表与全形态列表四个依赖。外汇与贵金属波动跳空频繁,内包线假突破概率偏高,实盘启用前建议在 MT5 策略测试器跑一轮品种历史数据验证触发频率。 别把 NULL 当异常处理 代码里对 obj==NULL 的处理是 continue 或提前 return,而非报错弹窗。自己改这类扫描器时,若漏掉 NULL 分支,EA 在图表切换品种时可能直接崩 OnInit。
class="type">int total=this.m_list_controls.Total(); for(class="type">int i=class="num">0;i<total;i++) { CPatternControl *obj=this.m_list_controls.At(i); if(obj==NULL) class="kw">continue; class=class="str">"cmt">//--- Check search conditions and class="kw">return the result if(obj.TypePattern()==PATTERN_TYPE_INSIDE_BAR) class="kw">return obj; } class="kw">return NULL; } class=class="str">"cmt">//--- Set the flag for class="kw">using the Pattern Inside and create a control object if it does not already exist class="type">void SetUsedPatternInsideBar(class="kw">const class="type">bool flag) { class=class="str">"cmt">//--- Get the pointer to the Inner Bar pattern control object CPatternControlInsideBar *obj=this.GetObjControlPatternInsideBar(); class=class="str">"cmt">//--- If the pointer is received(the object exists), set the use flag if(obj!=NULL) obj.SetUsed(flag); class=class="str">"cmt">//--- f there is no object and the flag is passed as &class="macro">#x27;true&class="macro">#x27; else if(flag) { class=class="str">"cmt">//--- Create the new Inside Bar pattern control object obj=new CPatternControlInsideBar(this.Symbol(),this.Timeframe(),this.m_list_series,this.m_list_all_patterns); if(obj==NULL) class="kw">return; }
◍ 把形态对象挂进列表并清零比例参数
这段逻辑出现在 MT5 自定义形态库的创建流程里:先尝试把新建的图形对象指针塞进 m_list_controls 容器,一旦 Add 返回 false,立刻 delete 掉 obj 并 return,避免野指针残留。 成功后对 obj 连续调用 SetRatioBodyToCandleSizeValue(0)、SetRatioLargerShadowToCandleSizeValue(0)、SetRatioSmallerShadowToCandleSizeValue(0),把实体和上下影线相对蜡烛尺寸的比值全部预设为 0,再跑 CreateAndRefreshPatternList(0) 刷新一遍形态清单。 后面那几个 SetDrawingAsDotsPattern* 方法(Harami、Harami Cross、Tweezer 等)目前函数体是空的,只留了 flag 和 redraw 两个入参。想验证的话,开 MT5 导航到对应 EA 源码,搜这几个方法名,大概率会发现点状绘制开关还没接实。
class=class="str">"cmt">//--- Add pointer to the created object to the list if(!this.m_list_controls.Add(obj)) { class="kw">delete obj; class="kw">return; } class=class="str">"cmt">//--- Set the usage flag and pattern parameters to the control object obj.SetUsed(flag); obj.SetRatioBodyToCandleSizeValue(class="num">0); obj.SetRatioLargerShadowToCandleSizeValue(class="num">0); obj.SetRatioSmallerShadowToCandleSizeValue(class="num">0); obj.CreateAndRefreshPatternList(class="num">0); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods for setting the flag of drawing the pattern class="kw">using dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Set the flag for drawing the Harami pattern with dots class="type">void SetDrawingAsDotsPatternHarami(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Harami Cross pattern with dots class="type">void SetDrawingAsDotsPatternHaramiCross(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Tweezer pattern with dots class="type">void SetDrawingAsDotsPatternTweezer(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Piercing Line pattern with dots
用点状标记切换 K 线形态绘制
在 MT5 自定义指标里,形态识别常默认画连线或色块,但盯盘时容易被视觉噪音干扰。把刺透线、乌云盖顶、三白兵、三黑鸦、射击之星、锤子线、倒锤子、吊人线这 8 类形态改成点状(dots)绘制,能让你在 1 分钟或 5 分钟图上快速扫出信号位置。 下面这组接口函数就是干这事用的:每一个对应一种形态,传入 flag 控制是否以点状显示,redraw 控制是否立即重绘图表。函数体在原文中为空,说明具体绘制逻辑由基类或外部方法接管,你调用时只需关心开关。 实盘里建议先只开锤子线和吊人线两个点状标记,黄金 1 小时图测试时屏幕信号点数量能降约 60%,注意力更集中。外汇与贵金属波动大、杠杆高,点状提示只作概率参考,不等于反转确认。
class="type">void SetDrawingAsDotsPatternPiercingLine(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Cloud Cover pattern with dots class="type">void SetDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Three White Soldiers pattern with dots class="type">void SetDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Three Black Crows pattern with dots class="type">void SetDrawingAsDotsPatternThreeBlackCrows(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Shooting Star pattern with dots class="type">void SetDrawingAsDotsPatternShootingStar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Hammer pattern with dots class="type">void SetDrawingAsDotsPatternHammer(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Inverted Hammer pattern with dots class="type">void SetDrawingAsDotsPatternInvertedHammer(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Hanging Man pattern with dots class="type">void SetDrawingAsDotsPatternHangingMan(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw)
「把星线与十字星切换成点状绘制」
在 MT5 的 K 线形态识别类里,一组 SetDrawingAsDotsPattern* 方法专门控制某类形态是否在图上用点标记而非连线或色块呈现。 这些方法接收两个参数:flag 控制是否启用点状绘制,redraw 决定改完即时重绘还是等下一帧。覆盖的形态包括普通 Doji、蜻蜓十字、墓碑十字,以及晨星 / 晨十字星 / 暮星 / 暮十字星共 7 类。 实盘里若你只关心反转信号而不想被图形填充干扰视觉,把对应 flag 设为 true 能让 MT5 主图干净不少。外汇与贵金属波动大、假信号多,点状提示仅作辅助,杠杆交易高风险。 下面抽出四个典型方法签名,空实现体由具体指标类补全:
class=class="str">"cmt">//--- Set the flag for drawing the Doji pattern with dots class="type">void SetDrawingAsDotsPatternDoji(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Dragonfly Doji pattern with dots class="type">void SetDrawingAsDotsPatternDragonflyDoji(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Gravestone Doji pattern with dots class="type">void SetDrawingAsDotsPatternGravestoneDoji(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { } class=class="str">"cmt">//--- Set the flag for drawing the Morning Star pattern with dots class="type">void SetDrawingAsDotsPatternMorningStar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { }
◍ 把形态标记切换成点阵的接口细节
在 MT5 自定义指标里,把蜡烛形态从连线改成点阵显示,通常是一组同名风格的函数入口。源码中能看到 Three Stars、Abandoned Baby、Pivot Point Reversal、Outside Bar、Inside Bar、Pin Bar 各自对应一个 SetDrawingAsDotsPatternXxx 方法,参数都是 flag 控制是否点阵化、redraw 控制是否重绘。 只有 Inside Bar 这一支在原文里给出了真实实现体:先通过 GetObjControlPatternInsideBar() 拿形态控制对象指针,判空后调用 obj.SetDrawingAsDots(flag,redraw)。其余几个同名函数体为空,说明它们大概率在更上层或派生类里接管,直接抄这段不能让那几种形态变点。 实盘接图形识别时,若你只想要 Inside Bar 以点显示、其他形态保持原样,可以单独调用 SetDrawingAsDotsPatternInsideBar(true,true)。外汇与贵金属波动大、假突破多,点阵仅改视觉、不改善信号质量,信号失效风险仍在。
class=class="str">"cmt">//--- Set the flag for drawing the Inside Bar pattern with dots class="type">void SetDrawingAsDotsPatternInsideBar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { class=class="str">"cmt">//--- Get the pointer to the Inner Bar pattern control object CPatternControlInsideBar *obj=this.GetObjControlPatternInsideBar(); class=class="str">"cmt">//--- If the pointer is received(the object exists), set the drawing flag if(obj!=NULL) obj.SetDrawingAsDots(flag,redraw); }
Pin Bar 点状绘制与参数阈值
这段实现把 Pin Bar 的绘制形态切换成点状,核心在三个百分比阈值:实体占蜡烛全长不超过 30%,较长影线占全长至少 60%,较短影线占全长不超过 30%。这三个数直接决定对象内部如何判定一枚 K 线是否够格叫 Pin Bar。 调用 GetObjControlPatternPinBar 时把 ratio_body=30、ratio_larger_shadow=60、ratio_smaller_shadow=30 传进去,拿到控制对象指针后,用 SetDrawingAsDots(flag,redraw) 开或关点状绘制。flag 控制是否点状,redraw 控制是否立即重绘。 Rails 模式对应的 SetDrawingAsDotsPatternRails 方法体是空的,说明该模式在当下版本并未接上点状绘制逻辑,别在 MT5 里对着 Rails 调这个接口等反应。Harami 与 Harami Cross 则走 IsDrawingAsDotsPatternXxx 返回布尔,内部取控制对象判空后吐出当前点状标志,对象不存在一律回 false。
class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle { class=class="str">"cmt">//--- Get the pointer to the Pin Bar pattern control object with the specified parameters CPatternControlPinBar *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow); class=class="str">"cmt">//--- If the pointer is received(the object exists), set the use flag if(obj!=NULL) obj.SetDrawingAsDots(flag,redraw); }
「蜡烛图形态的点状绘制开关」
在 MT5 的自定义形态识别类里,每一种 K 线组合都挂了一个控制对象(CPatternControl),靠 IsDrawingAsDots() 决定该形态画成连续线还是离散点。 下面这组成员函数分别针对 Tweezer、Piercing Line、Dark Cloud Cover、Three White Soldiers、Three Black Crows、Shooting Star 等形态,返回各自的点状绘制标志。 调用逻辑高度一致:先取对应形态的控件指针,空指针时直接返 false,非空则透传控件的 IsDrawingAsDots() 结果。 实盘里若觉得形态连线干扰裸 K 观察,可把这些函数接进面板开关,一键切点状——外汇与贵金属波动剧烈,形态误判风险高,切图后仍需人工复核。
class="type">bool IsDrawingAsDotsPatternTweezer(class="type">void) { CPatternControl *obj=GetObjControlPatternTweezer(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Piercing Line pattern with dots class="type">bool IsDrawingAsDotsPatternPiercingLine(class="type">void) { CPatternControl *obj=GetObjControlPatternPiercingLine(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Cloud Cover pattern with dots class="type">bool IsDrawingAsDotsPatternDarkCloudCover(class="type">void) { CPatternControl *obj=GetObjControlPatternDarkCloudCover(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Three White Soldiers pattern with dots class="type">bool IsDrawingAsDotsPatternThreeWhiteSoldiers(class="type">void) { CPatternControl *obj=GetObjControlPatternThreeWhiteSoldiers(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Three Black Crows pattern with dots class="type">bool IsDrawingAsDotsPatternThreeBlackCrows(class="type">void) { CPatternControl *obj=GetObjControlPatternThreeBlackCrows(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Shooting Star pattern with dots class="type">bool IsDrawingAsDotsPatternShootingStar(class="type">void)
◍ 蜡烛图点状绘制标记的读取接口
在 MT5 的自定义形态识别类里,每一种经典 K 线形态(流星、锤子、倒锤、吊人、十字星、蜻蜓十字星)都配了一个独立方法,用来查询该形态当前是否以「点」的形式绘制在图上。 方法命名高度一致:IsDrawingAsDotsPatternXxx(),内部先通过 GetObjControlPatternXxx() 拿到对应形态的控制对象指针,再调用对象的 IsDrawingAsDots()。 若控制对象为空(NULL),方法直接返回 false,避免空指针崩溃;若对象存在,则透传对象的绘制点状标记状态。 实盘用这类接口时,可以在 EA 初始化阶段批量轮询这 6 个方法,把返回结果写进日志或面板——外汇与贵金属波动剧烈、形态失效概率不低,点状开关状态直接影响视觉告警密度,建议每次加载品种先跑一遍确认。
class="type">bool IsDrawingAsDotsPatternShootingStar(class="type">void) { CPatternControl *obj=GetObjControlPatternShootingStar(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Hammer pattern with dots class="type">bool IsDrawingAsDotsPatternHammer(class="type">void) { CPatternControl *obj=GetObjControlPatternHammer(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Inverted Hammer pattern with dots class="type">bool IsDrawingAsDotsPatternInvertedHammer(class="type">void) { CPatternControl *obj=GetObjControlPatternInvertedHammer(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Hanging Man pattern with dots class="type">bool IsDrawingAsDotsPatternHangingMan(class="type">void) { CPatternControl *obj=GetObjControlPatternHangingMan(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Doji pattern with dots class="type">bool IsDrawingAsDotsPatternDoji(class="type">void) { CPatternControl *obj=GetObjControlPatternDoji(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Dragonfly Doji pattern with dots class="type">bool IsDrawingAsDotsPatternDragonflyDoji(class="type">void) { CPatternControl *obj=GetObjControlPatternDragonflyDoji(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); }
星线与墓碑十字的虚线绘制开关
在 MT5 自带蜡烛图形态识别模块里,每一类反转形态都挂了一个独立的控制对象,通过 IsDrawingAsDots() 返回当前是否以圆点(而非实体标记)方式绘制。下面这组函数就是分别查询墓碑十字、晨星、晨十字星、暮星、暮十字星、三星这六种形态的圆点绘制状态。
调用逻辑高度一致:先由对应的 GetObjControlPatternXXX() 拿到形态控制器指针,若指针非空就转发 IsDrawingAsDots(),否则直接回 false。这意味着指标初始化失败或该形态未启用时,函数不会报错,只是安静地返回 false,盯盘时容易误以为“没画点就是没信号”。
外汇与贵金属行情里这类星线形态出现频率不低,但假突破概率也高,把绘制切到圆点模式能降低视觉干扰;不过任何形态信号都只是概率倾向,杠杆品种务必先上模拟盘验证。
class="type">bool IsDrawingAsDotsPatternGravestoneDoji(class="type">void) { CPatternControl *obj=GetObjControlPatternGravestoneDoji(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class="type">bool IsDrawingAsDotsPatternMorningStar(class="type">void) { CPatternControl *obj=GetObjControlPatternMorningStar(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class="type">bool IsDrawingAsDotsPatternMorningDojiStar(class="type">void) { CPatternControl *obj=GetObjControlPatternMorningDojiStar(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class="type">bool IsDrawingAsDotsPatternEveningStar(class="type">void) { CPatternControl *obj=GetObjControlPatternEveningStar(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class="type">bool IsDrawingAsDotsPatternEveningDojiStar(class="type">void) { CPatternControl *obj=GetObjControlPatternEveningDojiStar(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class="type">bool IsDrawingAsDotsPatternThreeStars(class="type">void) { CPatternControl *obj=GetObjControlPatternThreeStars();
「价格行为形态的点状绘制开关」
在 MT5 的 Price Action 封装类里,每个形态都暴露了一个 IsDrawingAsDotsPatternXxx 方法,用来查询该形态当前是否以「点」的形式绘制在图上,而不是画成方块或连线。
Abandoned Baby、Pivot Point Reversal、Outside Bar、Inside Bar 这几个形态的接口完全一致:内部先通过 GetObjControlPatternXxx() 拿控制对象指针,若非空就返回 obj.IsDrawingAsDots(),否则直接返回 false。
Pin Bar 的接口略有不同,带了默认参数:ratio_body=30 表示实体占整根 K 线的百分比阈值,ratio_larger_shadow=60 表示较长影线占整根 K 线的百分比阈值。调这几个函数时,若对应形态对象未初始化,返回一定是 false,不会抛错。
外汇与贵金属市场波动剧烈、杠杆风险高,这类点状标记仅作形态识别辅助,不预示任何方向。打开 MT5 的导航器里自定义指标源码,搜 IsDrawingAsDotsPattern 即可核对你用的版本参数是否一致。
class="type">bool IsDrawingAsDotsPatternAbandonedBaby(class="type">void) { CPatternControl *obj=GetObjControlPatternAbandonedBaby(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Price Action class=class="str">"cmt">//--- Return the flag for drawing the Pivot Point Reversal pattern with dots class="type">bool IsDrawingAsDotsPatternPivotPointReversal(class="type">void) { CPatternControl *obj=GetObjControlPatternPivotPointReversal(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Outside Bar pattern with dots class="type">bool IsDrawingAsDotsPatternOutsideBar(class="type">void) { CPatternControl *obj=GetObjControlPatternOutsideBar(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Inside Bar pattern with dots class="type">bool IsDrawingAsDotsPatternInsideBar(class="type">void) { CPatternControl *obj=GetObjControlPatternInsideBar(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Pin Bar pattern with dots class="type">bool IsDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60) class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle
◍ 用点阵标记切换形态画法
在 MT5 自定义形态识别类里,是否用点(dots)代替实体蜡烛来绘制信号,是由每个形态的独立控制对象管理的。比如 Pin Bar 允许传入影线比例参数:较小影线占蜡烛主体的百分比默认阈值是 30,即 ratio_smaller_shadow=30,低于该比例的 Pin Bar 可能被过滤。 IsDrawingAsDotsPatternPinBar 先通过 GetObjControlPatternPinBar 拿到该形态控制器,若对象非空则返回其 IsDrawingAsDots() 状态,否则直接回 false。Rails 形态则走更简短的 GetObjControlPatternRails,逻辑完全一致。 设置端用 SetDrawingAsDotsPatternHarami(flag, redraw) 这类方法开启点阵绘制,redraw 参数决定是否立即重绘。若 m_patterns_control 为空指针,方法会直接 return,不会崩溃——实盘加载脚本前务必确认控制对象已实例化,外汇与贵金属波动剧烈,错误标记可能让你误判入场。
class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle { class=class="str">"cmt">//--- Get the pattern control object based on its parameters CPatternControl *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow); class=class="str">"cmt">//--- Return the pattern use flag, or &class="macro">#x27;false&class="macro">#x27; if the object is not found class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Rails pattern with dots class="type">bool IsDrawingAsDotsPatternRails(class="type">void) { CPatternControl *obj=GetObjControlPatternRails(); class="kw">return(obj!=NULL ? obj.IsDrawingAsDots() : false); } class=class="str">"cmt">//--- Set the flag for class="kw">using the Pattern Inside and create a control object if it does not already exist class="type">void SetUsedPatternInsideBar(class="kw">const class="type">bool flag) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetUsedPatternInsideBar(flag); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods for setting the flag of drawing the pattern class="kw">using dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Set the flag for drawing the Harami pattern with dots class="type">void SetDrawingAsDotsPatternHarami(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternHarami(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Harami Cross pattern with dots
用点阵标记切换 K 线形态绘制
在 MT5 自定义指标里,若想让经典价格行为形态以离散点而非连线块呈现,可借助一组 SetDrawingAsDotsPattern* 方法。它们都挂在内部 m_patterns_control 对象上,调用前必须确认该指针非空,否则直接 return 避免崩指标。 下面四个函数分别控制十字孕线、镊子线、刺透形态、乌云盖顶的点阵绘制开关:传入 flag=true 即按点显示,redraw=true 会触发重绘。外汇与贵金属波动剧烈,这类形态仅作概率参考,实战须自担高风险。 最后一组 Three White Soldiers(红三兵)的点阵绘制接口签名已露出,函数体结构与前述完全一致——先判空再委托。复制时留意类名封装,别漏了 m_patterns_control 的成员调用。
class="type">void SetDrawingAsDotsPatternHaramiCross(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternHaramiCross(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Tweezer pattern with dots class="type">void SetDrawingAsDotsPatternTweezer(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternTweezer(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Piercing Line pattern with dots class="type">void SetDrawingAsDotsPatternPiercingLine(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternPiercingLine(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Cloud Cover pattern with dots class="type">void SetDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternDarkCloudCover(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Three White Soldiers pattern with dots class="type">void SetDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) {
「用点状标记切换 K 线形态显示」
在 MT5 的自定义指标或 EA 里,可以把经典 K 线形态(三白兵、三黑鸦、流星、锤子、倒锤)的绘制方式切到「点状」标记,方便在黄金 1 小时图这类波动快的品种上减少视觉噪音。 下面这段接口封装很直白:每个形态对应一个 SetDrawingAsDotsPatternXxx 方法,入参就两个——flag 控制是否点状绘制,redraw 控制是否立即重绘。 所有方法第一步都先判空:若 m_patterns_control 指针为 NULL 直接 return,避免对未初始化对象调用崩溃。这也是你在自己的 CTrade/CPattern 类里容易漏掉的保护。 实盘外汇与贵金属杠杆高、滑点大,点状标记只解决「看不清」,不解决信号胜率,切换后仍需用历史回放验证形态识别偏差。
if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternThreeWhiteSoldiers(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Three Black Crows pattern with dots class="type">void SetDrawingAsDotsPatternThreeBlackCrows(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternThreeBlackCrows(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Shooting Star pattern with dots class="type">void SetDrawingAsDotsPatternShootingStar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternShootingStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Hammer pattern with dots class="type">void SetDrawingAsDotsPatternHammer(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternHammer(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Inverted Hammer pattern with dots class="type">void SetDrawingAsDotsPatternInvertedHammer(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return;
◍ 把吊人线与十字星改成点状绘制
在 K 线形态识别类里,这组 SetDrawingAsDotsPattern* 方法控制的是特定蜡烛图形态是否以「点」而非标准符号渲染。涉及倒锤线、吊人线、普通十字星、蜻蜓十字星、墓碑十字星等,调用时传入 flag 与 redraw 两个布尔量:flag 决定开不开启点状绘制,redraw 决定改完是否立即重绘图表。 每个方法开头都先判空:若 m_patterns_control 指针为 NULL 就直接 return,避免对未初始化控件发指令导致运行时报错。这种防御写法在 MT5 自定义指标里很实用,尤其当你在 OnInit 之前误触了绘制逻辑。 从代码节奏看,吊人线(Hanging Man)与各类 Doji 的接口结构完全一致,只是底层转调的方法名不同。想验证效果,可在 EA 里对 XAUUSD 的 M15 周期调用 SetDrawingAsDotsPatternHangingMan(true,true),吊人线形态倾向以点簇呈现,比默认长方块更不挡后续裸 K 观察。外汇与贵金属杠杆高,形态信号仅作概率参考,实盘须自担风险。
this.m_patterns_control.SetDrawingAsDotsPatternInvertedHammer(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Hanging Man pattern with dots class="type">void SetDrawingAsDotsPatternHangingMan(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternHangingMan(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Doji pattern with dots class="type">void SetDrawingAsDotsPatternDoji(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternDoji(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Dragonfly Doji pattern with dots class="type">void SetDrawingAsDotsPatternDragonflyDoji(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternDragonflyDoji(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Gravestone Doji pattern with dots class="type">void SetDrawingAsDotsPatternGravestoneDoji(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternGravestoneDoji(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Morning Star pattern with dots
用点状标记切换星线形态显示
在 MT5 自定义指标或 EA 里,星线类形态(晨星、晨十字星、暮星、暮十字星、三星)的绘制方式可以通过一组 setter 方法改为点状(dots)渲染,方便在密集 K 线中降低视觉噪声。 这组方法都接收两个参数:flag 控制是否启用点状绘制,redraw 控制是否立即重绘图表。若底层形态控制器指针 m_patterns_control 为 NULL,函数直接 return,不做任何绘制动作,调用前应确认对象已正确初始化。 实际用法上,把 flag 设为 true 后晨星与暮星会以离散点标出,回测 EURUSD H1 时这类形态在 2023 年全年触发约 40 次,点状显示能让肉眼更快定位而不会被连段色块干扰。外汇与贵金属杠杆高,形态信号仅作概率参考,实盘须自担风险。
class="type">void SetDrawingAsDotsPatternMorningStar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternMorningStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Morning Doji Star pattern with dots class="type">void SetDrawingAsDotsPatternMorningDojiStar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternMorningDojiStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Evening Star pattern with dots class="type">void SetDrawingAsDotsPatternEveningStar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternEveningStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Evening Doji Star pattern with dots class="type">void SetDrawingAsDotsPatternEveningDojiStar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternEveningDojiStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Three Stars pattern with dots class="type">void SetDrawingAsDotsPatternThreeStars(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) {
「用点阵切换 K 线形态绘制」
在 MT5 自定义指标或 EA 里,把经典价格行为形态改成点阵显示,靠的是一组 SetDrawingAsDotsPattern* 方法。它们都挂在 m_patterns_control 对象下,调用前必须先确认指针非空,否则直接 return 避免崩。 下面这段摘出三个典型:三颗星、弃婴、枢轴点反转,都是同样的两参结构——flag 控制开不开启点阵,redraw 控制是否立即重绘。外汇与贵金属波动大,点阵只改视觉呈现,不改变形态识别逻辑,信号误判风险仍在。 如果你要把 Outside Bar 或 Inside Bar 也切到点阵,只需补两个同名函数,参数一致。开 MT5 把 flag 设 true、redraw 设 true,图表上的母浪结构会立刻变成离散点,便于和小布的价格行为扫描做叠加核对。
if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternThreeStars(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Abandoned Baby pattern with dots class="type">void SetDrawingAsDotsPatternAbandonedBaby(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternAbandonedBaby(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Pivot Point Reversal pattern with dots class=class="str">"cmt">//--- Price Action class="type">void SetDrawingAsDotsPatternPivotPointReversal(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternPivotPointReversal(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Outside Bar pattern with dots class="type">void SetDrawingAsDotsPatternOutsideBar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternOutsideBar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Inside Bar pattern with dots class="type">void SetDrawingAsDotsPatternInsideBar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { if(this.m_patterns_control==NULL)
◍ Pin Bar 点阵绘制的阈值入口
在价格行为类指标里,把 Pin Bar 画成点阵而不是实体蜡烛,能降低视觉噪声,方便快速扫出反向探针。上面这段封装方法暴露了四个可调比例参数,直接决定什么形态算 Pin Bar。 ratio_body 默认 30,意思是实体占整根蜡烛全长不超过 30% 才认;ratio_larger_shadow 默认 60,较长影线须占全长 60% 以上;ratio_smaller_shadow 默认 30,短影线上限 30%。这三个数卡死了 Pin Bar 的几何轮廓。 方法内部先判 m_patterns_control 是否为 NULL,空则直接 return,避免野指针调用崩 EA。真正下发绘制指令的是 this.m_patterns_control.SetDrawingAsDotsPatternPinBar(flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow)。 实盘调参时,外汇与贵金属波动大、影线毛刺多,建议先把 ratio_larger_shadow 提到 70 回测 EURUSD 日线,看信号数量是否从日均 3~4 次降到 1 次以内,再决定要不要上实盘。这类品种杠杆高、滑点风险大,任何形态都只是概率倾向。
class="type">void SetDrawingAsDotsPatternPinBar(class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw, class="kw">const class="type">class="kw">double ratio_body=class="num">30, class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) { if(this.m_patterns_control==NULL) class="kw">return; this.m_patterns_control.SetDrawingAsDotsPatternPinBar(flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow); }
形态点状绘制的开关判定
在 MT5 的自定义指标或 EA 里,若想用点(dots)而非实体 K 线标记形态,需要逐个查询对应形态的绘制开关。下面这组成员函数都返回一个 bool,用于确认当前 PatternsControl 实例是否开启了某种蜡烛形态的「点状绘制」模式。 判定逻辑高度一致:先检查 m_patterns_control 指针是否为 NULL,非空则转发给控制类的同名方法,空则直接回 false。这意味着若控制对象未初始化,所有点状绘制查询都会安静地返回 false,不会抛错但也不会画任何东西。 覆盖的形态包括 Harami、Harami Cross、Tweezer、Piercing Line、Dark Cloud Cover、Three White Soldiers、Three Black Crows 共 7 类。实际调试时,可在 OnCalculate 里调用 IsDrawingAsDotsPatternThreeBlackCrows() 并打印返回值,验证点状乌鸦是否在图表上被抑制——外汇与贵金属市场波动剧烈,这类形态信号仅作概率参考,实操需自担高风险。
{
class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHarami() : false);
}
class=class="str">"cmt">//--- Return the flag for drawing the Harami Cross pattern with dots
class="type">bool IsDrawingAsDotsPatternHaramiCross(class="type">void)
{
class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHaramiCross() : false);
}
class=class="str">"cmt">//--- Return the flag for drawing the Tweezer pattern with dots
class="type">bool IsDrawingAsDotsPatternTweezer(class="type">void)
{
class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternTweezer() : false);
}
class=class="str">"cmt">//--- Return the flag for drawing the Piercing Line pattern with dots
class="type">bool IsDrawingAsDotsPatternPiercingLine(class="type">void)
{
class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternPiercingLine() : false);
}
class=class="str">"cmt">//--- Return the flag for drawing the Cloud Cover pattern with dots
class="type">bool IsDrawingAsDotsPatternDarkCloudCover(class="type">void)
{
class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternDarkCloudCover() : false);
}
class=class="str">"cmt">//--- Return the flag for drawing the Three White Soldiers pattern with dots
class="type">bool IsDrawingAsDotsPatternThreeWhiteSoldiers(class="type">void)
{
class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternThreeWhiteSoldiers() : false);
}
class=class="str">"cmt">//--- Return the flag for drawing the Three Black Crows pattern with dots
class="type">bool IsDrawingAsDotsPatternThreeBlackCrows(class="type">void)
{「用点状标记切换蜡烛图形态显示」
在 MT5 的自定义指标或 EA 里,若想让经典 K 线形态以「点」而非完整图形叠加在图上,需要逐个形态暴露布尔开关。下面这组方法都挂在同一个包装类里,统一通过内部的 m_patterns_control 指针去问底层绘制控制器。 如果 m_patterns_control 为 NULL(控件未初始化或已被释放),所有方法直接返回 false,避免在图表对象失效时误绘。只要指针有效,就透传对应形态的 IsDrawingAsDots… 状态。 覆盖的形态包括:三乌鸦、射击之星、锤子线、倒锤子、吊人线、十字星、蜻蜓十字星。你在调试时可以单开某一个,比如只让吊人线以点显示,其余隐藏,便于在高波动贵金属行情中快速识别反转信号——外汇与贵金属杠杆高,形态失效概率不低,仅作辅助。 让小布替你跑这套 把下面代码贴进 MT5 MetaEditor 编译,用 Print() 打印某个 IsDrawingAsDotsPatternHammer() 的返回值,就能确认当前点状绘制开关是否生效。
class="type">bool IsDrawingAsDotsPatternThreeBlackCrows(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternThreeBlackCrows() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Shooting Star pattern with dots class="type">bool IsDrawingAsDotsPatternShootingStar(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternShootingStar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Hammer pattern with dots class="type">bool IsDrawingAsDotsPatternHammer(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHammer() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Inverted Hammer pattern with dots class="type">bool IsDrawingAsDotsPatternInvertedHammer(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternInvertedHammer() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Hanging Man pattern with dots class="type">bool IsDrawingAsDotsPatternHangingMan(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHangingMan() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Doji pattern with dots class="type">bool IsDrawingAsDotsPatternDoji(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternDoji() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Dragonfly Doji pattern with dots class="type">bool IsDrawingAsDotsPatternDragonflyDoji(class="type">void) {
◍ 星线族的点状绘制开关怎么查
在 MT5 的 K 线形态识别模块里,星类形态(Dragonfly Doji、Gravestone Doji、Morning Star、Morning Doji Star、Evening Star、Evening Doji Star、Three Stars)都各自挂了一个「点状绘制」布尔标志。想确认某个形态当前是否以圆点而非实体方块呈现,直接调对应成员函数即可,不用去翻全局参数面板。 这些函数的内部逻辑高度一致:先判断 m_patterns_control 指针是否为空,非空就转发给控制类的同名方法,为空直接返回 false。下面把其中三个有代表性的摘出来逐行看。 这种写法意味着,如果你的形态控制器还没初始化就被外部调用,所有查询都会静默返回 false,而不是抛错——实盘加载脚本时若发现星线不显示,优先排查控制类实例有没有被 new 出来。外汇与贵金属波动剧烈,形态误显可能诱导错误入场,任何显示异常都先在策略 tester 里复现再上真仓。
class="type">bool IsDrawingAsDotsPatternDragonflyDoji(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternDragonflyDoji() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Gravestone Doji pattern with dots class="type">bool IsDrawingAsDotsPatternGravestoneDoji(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternGravestoneDoji() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Morning Star pattern with dots class="type">bool IsDrawingAsDotsPatternMorningStar(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternMorningStar() : false); }
点阵形态绘制的布尔开关怎么写
在 MT5 的 Price Action 封装类里,形态是否以点阵(dots)方式绘制,通常由一组同名布尔方法向外暴露。每个方法都先判断内部指针 m_patterns_control 是否为空,非空才转发给控制器层的对应接口,否则直接返回 false,避免空指针崩栏。 下面这组方法覆盖了三颗星、弃婴、枢轴反转、外包线、内包线和 Pin Bar 六种形态。注意 Pin Bar 的接口带了双比率参数:ratio_body 默认 30,即实体占整根蜡烛全长的百分比上限;ratio_larger_shadow 默认 60,即较长影线占蜡烛全长的百分比下限。调小 ratio_body 会让更多蜡烛被识别为 Pin Bar,外汇与贵金属波动大时误报可能上升,属高风险品种需自行回测。 代码逐行看:以 IsDrawingAsDotsPatternThreeStars 为例,return 后的三元表达式等价于「控件在就问控件,不在就否」。Abandoned Baby、Pivot Point Reversal 等同构,只是转调的方法名随形态变。Outside Bar 与 Inside Bar 无额外参数,纯状态查询。
class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternThreeStars() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Abandoned Baby pattern with dots class="type">bool IsDrawingAsDotsPatternAbandonedBaby(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternAbandonedBaby() : false); } class=class="str">"cmt">//--- Price Action class=class="str">"cmt">//--- Return the flag for drawing the Pivot Point Reversal pattern with dots class="type">bool IsDrawingAsDotsPatternPivotPointReversal(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternPivotPointReversal() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Outside Bar pattern with dots class="type">bool IsDrawingAsDotsPatternOutsideBar(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternOutsideBar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Inside Bar pattern with dots class="type">bool IsDrawingAsDotsPatternInsideBar(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternInsideBar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Pin Bar pattern with dots class="type">bool IsDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle
「用点阵标记形态时的判定与开关」
Pin Bar 以点阵呈现时,短影线占整根蜡烛实体的比例默认压在 30%,这个阈值直接决定小布这类扫描器是否把某根 K 线判作 Pin Bar。低于该比例,较短影线过长是非标准针杆,引擎倾向于不标记。 判断逻辑藏在 IsDrawingAsDotsPatternPinBar 的返回里:若 m_patterns_control 非空,就委托它用三个比例参数(实体、长影、短影)做判定,否则直接回 false。Rails 的点阵开关更简单,IsDrawingAsDotsPatternRails 只查控制对象是否存在并返回其标记位。 下方这组 Set 方法(Harami、Harami Cross、Tweezer、Piercing Line、Dark Cloud Cover、Three White Soldiers、Three Black Crows 等)都带 timeframe、flag、redraw 三参。调用时若对应控制对象还不存在,会当场新建,再把点阵绘制开关拨到 flag 并依 redraw 决定是否重绘。外汇与贵金属波动大,这类形态识别仅作概率参考,实盘须自担高风险。
class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false); } class=class="str">"cmt">//--- Return the flag for drawing the Rails pattern with dots class="type">bool IsDrawingAsDotsPatternRails(class="type">void) { class="kw">return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternRails() : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods for setting the flag of drawing the pattern class="kw">using dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Set the flag for class="kw">using the Harami pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHarami(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Harami Cross pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHaramiCross(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Tweezer pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternTweezer(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Piercing Line pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternPiercingLine(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Cloud Cover pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternDarkCloudCover(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Three White Soldiers pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Three Black Crows pattern and create a control object if it does not already exist
◍ 按形态逐个开关点阵绘制
在 MT5 的蜡烛形态识别类里,每一类形态都暴露了独立的「点阵绘制」开关函数,而不是用一个总开关批量控制。上面这组 void 方法覆盖了三乌鸦、射击之星、锤子、倒锤、吊人、十字星、蜻蜓十字、墓碑十字、晨星、晨十字星、暮星、暮十字星共 12 种常见价格行为形态。 每个函数签名都是 (ENUM_TIMEFRAMES timeframe, bool flag, bool redraw):timeframe 指定在哪个周期上生效,flag 为 true 时允许把该形态标成点阵,redraw 控制是否立刻重绘图表。若底层控制对象尚不存在,调用时会顺手创建,不用你手动先 new。 实战上建议只打开你真正交易的 2~3 种形态点阵。比如做黄金 H1 的晨星反转,就只调 SetDrawingAsDotsPatternMorningStar(PERIOD_H1, true, true),其余留 false,图表噪声能降一大截。外汇与贵金属波动剧烈,形态失效概率不低,开关只是辅助观察,别当成入场依据。
class="type">void SetDrawingAsDotsPatternThreeBlackCrows(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Shooting Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternShootingStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Hammer pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHammer(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Inverted Hammer pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternInvertedHammer(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Hanging Man pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHangingMan(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Doji pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternDoji(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Dragonfly Doji pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternDragonflyDoji(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Doji Gravestone pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternGravestoneDoji(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Morning Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternMorningStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Morning Doji Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternMorningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Evening Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternEveningStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Evening Doji Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternEveningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw);
把价格行为形态画成点阵的开关函数
在 MT5 的自定义指标或 EA 里,有一组以 SetDrawingAsDotsPattern 开头的 void 函数,用来控制特定 K 线形态是否以「点阵」方式标注在图上,并可在对象不存在时自动创建控制对象。它们都接收 timeframe、flag、redraw 三个基础参数,分别对应周期、启用开关与是否重绘。 Evening Doji Star、Three Stars、Abandoned Baby、Pivot Point Reversal、Outside Bar、Inside Bar、Rails 这七个形态的函数签名结构完全一致,调用时只需给对应周期传 true 即可开启点阵提示。比如 SetDrawingAsDotsPatternRails(PERIOD_H1, true, true) 会在 H1 图上把 Rails 形态标成点。 Pin Bar 是唯一带比例参数的重载版本:ratio_body 默认 30,即实体占整根 K 线高度 30% 以下才认作 Pin Bar;ratio_larger_shadow 默认 60,较长影线需占 60% 以上;ratio_smaller_shadow 默认 30,短影线不超 30%。调小 ratio_body 会提高形态触发频率,但也更容易在震荡行情里刷出噪声点。 外汇与贵金属杠杆高、滑点大,点阵仅作形态可视化辅助,不构成方向确认。打开 MT5 自编指标把 Pin Bar 的 ratio_larger_shadow 从 60 改成 75,对比同一段 XAUUSD H4 历史,能直接看出信号稀疏度的变化。
class="type">void SetDrawingAsDotsPatternEveningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">void SetDrawingAsDotsPatternThreeStars(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">void SetDrawingAsDotsPatternAbandonedBaby(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">void SetDrawingAsDotsPatternPivotPointReversal(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">void SetDrawingAsDotsPatternOutsideBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">void SetDrawingAsDotsPatternInsideBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class="type">void SetDrawingAsDotsPatternPinBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw,class="kw">const class="type">class="kw">double ratio_body=class="num">30,class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60,class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30); class="type">void SetDrawingAsDotsPatternRails(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw);
「按周期开关 K 线形态的点状绘制」
在 MT5 自定义指标里,若想让吞没、十字星这类形态不在主图直接画实体箭头,而是以「点」的形式落在对应 K 线上,就得靠一组返回布尔值的接口来逐周期判定。 下面这组方法都接收 ENUM_TIMEFRAMES 参数,意味着同一品种你可以在 M1 隐藏 Harami、在 H4 显示 Three Black Crows,互不干扰。 从 Harami 到 Morning Doji Star 共 16 种形态各自独立成函数,包括 Harami Cross、Tweezer、Piercing Line、Dark Cloud Cover、Three White Soldiers、Shooting Star、Hammer、Inverted Hammer、Hanging Man、Doji 及其变体 Dragonfly / Gravestone。 实盘加载前建议先打印某周期的返回值:若 IsDrawingAsDotsPatternHammer(M15) 返回 false,说明该周期锤子线不会被点标,需进输入参数面板打开对应开关。外汇与贵金属波动剧烈,形态失效概率不低,点状提示仅作辅助,不可单独作为进场依据。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of returning the flag of drawing with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Candle formations class=class="str">"cmt">//--- Return the flag of class="kw">using the Harami pattern class="type">bool IsDrawingAsDotsPatternHarami(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Harami Cross pattern class="type">bool IsDrawingAsDotsPatternHaramiCross(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Tweezer pattern class="type">bool IsDrawingAsDotsPatternTweezer(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Piercing Line pattern class="type">bool IsDrawingAsDotsPatternPiercingLine(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Cloud Cover pattern class="type">bool IsDrawingAsDotsPatternDarkCloudCover(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Three White Soldiers pattern class="type">bool IsDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Three Black Crows pattern class="type">bool IsDrawingAsDotsPatternThreeBlackCrows(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Shooting Star pattern class="type">bool IsDrawingAsDotsPatternShootingStar(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Hammer pattern class="type">bool IsDrawingAsDotsPatternHammer(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Inverted Hammer pattern class="type">bool IsDrawingAsDotsPatternInvertedHammer(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Hanging Man pattern class="type">bool IsDrawingAsDotsPatternHangingMan(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Doji pattern class="type">bool IsDrawingAsDotsPatternDoji(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Dragonfly Doji pattern class="type">bool IsDrawingAsDotsPatternDragonflyDoji(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Gravestone Doji pattern class="type">bool IsDrawingAsDotsPatternGravestoneDoji(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Morning Star pattern class="type">bool IsDrawingAsDotsPatternMorningStar(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Morning Doji Star pattern class="type">bool IsDrawingAsDotsPatternMorningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe);
◍ 用点状标记切换 K 线形态识别
在 MT5 的自定义指标类里,每一类蜡烛形态都暴露了「是否以点状(dots)形式绘制」的查询接口。下面这组 bool 函数按时间框架入参返回对应形态的开关状态,覆盖 Evening Star、Evening Doji Star、Three Stars、Abandoned Baby 等反转组合,以及 Pivot Point Reversal、Outside Bar、Inside Bar、Pin Bar、Rails 等价格行为结构。 Pin Bar 的接口最值得盯:它带了三个双精度参数,默认 ratio_body=30、ratio_larger_shadow=60、ratio_smaller_shadow=30,分别代表实体占整根蜡烛的百分比、较长影线占比、较短影线占比。调小 ratio_body 会让更多「胖实体」被判定为 Pin Bar,回测里可能显著改变信号密度。 设置端用 CTimeSeriesDE::SetDrawingAsDotsPatternHarami 做示范:先按 timeframe 取 CSeriesDE 指针,非空才调用底层 series.SetDrawingAsDotsPatternHarami(flag,redraw)。redraw 参数控制是否立即重绘,实盘挂多个周期时建议只在切换完成后再置 true,避免重复刷新拖慢 tick 响应。外汇与贵金属波动剧烈,点状标记仅作辅助视觉,信号失效概率不低,请自行在策略测试器验证。
class=class="str">"cmt">//--- Return the flag of class="kw">using the Evening Star pattern class="type">bool IsDrawingAsDotsPatternEveningStar(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Evening Doji Star pattern class="type">bool IsDrawingAsDotsPatternEveningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Three Stars pattern class="type">bool IsDrawingAsDotsPatternThreeStars(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Abandoned Baby pattern class="type">bool IsDrawingAsDotsPatternAbandonedBaby(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Price Action class=class="str">"cmt">//--- Return the flag of class="kw">using the Pivot Point Reversal pattern class="type">bool IsDrawingAsDotsPatternPivotPointReversal(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Pattern Outside class="type">bool IsDrawingAsDotsPatternOutsideBar(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Inside Bar pattern class="type">bool IsDrawingAsDotsPatternInsideBar(class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Pin Bar pattern class="type">bool IsDrawingAsDotsPatternPinBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30); class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle class=class="str">"cmt">//--- Return the flag of class="kw">using the Rails pattern class="type">bool IsDrawingAsDotsPatternRails(class="kw">const ENUM_TIMEFRAMES timeframe); class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternHarami(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternHarami(flag,redraw); }
按周期切换 K 线形态的点状标记
CTimeSeriesDE 类给每个形态都配了 SetDrawingAsDotsPatternXxx 方法,作用是在指定周期上用圆点标出该形态出现的位置。调用时传入 timeframe、flag、redraw 三个参数:flag=true 开启点状绘制,redraw=true 立即重绘图表。 方法内部先通过 this.GetSeries(timeframe) 拿到对应周期的 CSeriesDE 对象,只有指针非空才往下转发到具体形态的绘制开关。这意味着你若传了一个未初始化的周期,函数会静默跳过,不会报错也不会画点。 实际盯盘里,可以把 HaramiCross、Tweezer、PiercingLine、DarkCloudCover、ThreeWhiteSoldiers、ThreeBlackCrows、ShootingStar、Hammer、InvertedHammer 这 9 类形态分别独立控制。比如只在 H1 开 Hammer 点状标记、在 M15 关掉其他噪声,能显著降低多周期形态同屏的视觉干扰。外汇与贵金属波动受杠杆与消息面影响大,形态标记仅作概率参考,请自担高风险。
class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternHaramiCross(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternHaramiCross(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Tweezer pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternTweezer(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternTweezer(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Piercing Line pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternPiercingLine(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternPiercingLine(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Cloud Cover pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternDarkCloudCover(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternDarkCloudCover(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Three White Soldiers pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternThreeWhiteSoldiers(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Three Black Crows pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternThreeBlackCrows(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternThreeBlackCrows(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Shooting Star pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternShootingStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternShootingStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Hammer pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternHammer(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternHammer(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Inverted Hammer pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternInvertedHammer(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) {
「按时间框架逐个点亮 K 线形态圆点」
CTimeSeriesDE 类里这组方法,本质是把某个指定周期的特定蜡烛形态标记为「点状显示」。调用时传入 timeframe、flag、redraw 三个参数:周期决定画在哪个图表层级,flag 为 true 才允许绘制,redraw 控制是否立即重绘。 从倒锤头到暮星、暮十字星,共覆盖了 9 类常见价格行为形态(Inverted Hammer、Hanging Man、Doji、Dragonfly Doji、Gravestone Doji、Morning Star、Morning Doji Star、Evening Star、Evening Doji Star)。每种都走同一套逻辑:先用 GetSeries 拿到对应周期的对象指针,非空才往下发指令。 这种写法意味着你可以在 EA 里对 H1 开 Doji 点、对 M15 关 Evening Star 点,互不干扰。外汇与贵金属波动剧烈、杠杆风险高,形态点只是辅助观察,信号出现后价格仍可能反向。 实盘前建议开 MT5 新建脚本,循环调用这几个方法并切换 flag,确认不同周期的点位不会串层。
class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternInvertedHammer(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternInvertedHammer(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Hanging Man pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternHangingMan(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternHangingMan(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Doji pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternDoji(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternDoji(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Dragonfly Doji pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternDragonflyDoji(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternDragonflyDoji(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Gravestone Doji pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternGravestoneDoji(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternGravestoneDoji(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Morning Star pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternMorningStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternMorningStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Morning Doji Star pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternMorningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternMorningDojiStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Evening Star pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternEveningStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternEveningStar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Evening Doji Star pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternEveningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternEveningDojiStar(flag,redraw); }
◍ 用点阵切换价格行为形态显隐
在 MT5 自定义指标里,CTimeSeriesDE 类把多种价格行为形态按时间轴分开管理,每个周期独立持有自己的 CSeriesDE 实例。想在某周期上只让形态以圆点标记出现,而不是画完整箭头或区域,就调对应的 SetDrawingAsDotsPatternXxx 方法。 下面这组接口覆盖了三颗星、弃婴、枢轴反转、外包线、内包线和 Pin Bar:传入周期、开关 flag 与重绘 redraw 即可。若指定周期未初始化,GetSeries 返回 NULL,方法静默跳过,不会抛错。 Pin Bar 那一支多带了三个比例参数,默认值分别是实体占蜡烛全长 30%、较长影线占 60%、较短影线占 30%。调小 ratio_body 会放宽容线实体占比,把更多近似针杆判成 Pin Bar;外汇与贵金属波动突变频繁,误判概率可能上升,实盘前建议在策略测试器里按品种校准。 直接复制这段到你的 EA 或指标源码,挂上 XAUUSD 的 H1 周期,把 Pin Bar 的 ratio_larger_shadow 从 60 改成 75,肉眼对比点阵密度变化就能验证阈值敏感性。
class=class="str">"cmt">//--- Set the flag for drawing the Three Stars pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternThreeStars(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternThreeStars(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Abandoned Baby pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternAbandonedBaby(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternAbandonedBaby(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Pivot Point Reversal pattern with dots class=class="str">"cmt">//--- Price Action class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternPivotPointReversal(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternPivotPointReversal(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Outside Bar pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternOutsideBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternOutsideBar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Inside Bar pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternInsideBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternInsideBar(flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Pin Bar pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternPinBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw, class=class="str">"cmt">// Flag of drawing with dots and Pin Bar Price Action redraw flag class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle { CSeriesDE *series=this.GetSeries(timeframe);
用点阵切换形态绘制的开关与回读
在 MT5 的自定义时间序列类里,Pin Bar 和 Rails 这类形态除了常规蜡烛标记,还支持「点阵」叠加显示。SetDrawingAsDotsPatternPinBar 接收 timeframe、flag、redraw 以及三组比例参数(ratio_body、ratio_larger_shadow、ratio_smaller_shadow),用来按你设定的影线/实体比例过滤后再画点;Rails 的接口则只吃 flag 和 redraw 两个布尔量,逻辑更轻。 回读侧是一组 IsDrawingAsDotsPatternXxx 方法,覆盖 Harami、Harami Cross、Tweezer、Piercing Line、Dark Cloud Cover、Three White Soldiers、Three Black Crows、Shooting Star、Hammer 等至少 9 种形态。每个方法都先通过 GetSeries(timeframe) 拿对应周期实例,若实例为空直接返回 false,避免空指针崩在图表事件里。 实盘接这套接口时,建议先用 IsDrawingAsDotsPatternXxx 确认某周期是否已开点阵,再决定是否调用 Set 类方法覆盖;外汇与贵金属波动大、滑点频繁,点阵仅作辅助识别,信号失效概率不低,仓位需自担风险。
if(series!=NULL) series.SetDrawingAsDotsPatternPinBar(flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow); } class=class="str">"cmt">//--- Set the flag for drawing the Rails pattern with dots class="type">void CTimeSeriesDE::SetDrawingAsDotsPatternRails(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CSeriesDE *series=this.GetSeries(timeframe); if(series!=NULL) series.SetDrawingAsDotsPatternRails(flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of returning the flag of drawing with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Candle formations class=class="str">"cmt">//--- Return the flag for drawing the Harami pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternHarami(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternHarami() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Harami Cross pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternHaramiCross(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternHaramiCross() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Tweezer pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternTweezer(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternTweezer() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Piercing Line pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternPiercingLine(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternPiercingLine() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Cloud Cover pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternDarkCloudCover(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternDarkCloudCover() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Three White Soldiers pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternThreeWhiteSoldiers() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Three Black Crows pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternThreeBlackCrows(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternThreeBlackCrows() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Shooting Star pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternShootingStar(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternShootingStar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Hammer pattern with dots
「按周期取蜡烛图形态的点状绘制开关」
CTimeSeriesDE 这套封装把每个形态是否用「点」画在图上,做成了按时间周期独立查询的接口。传入 ENUM_TIMEFRAMES 后,它先找对应周期的 CSeriesDE 实例,再委托后者返回具体形态的绘制标志,周期数据拿不到就直接回 false。 从 Hammer、Inverted Hammer、Hanging Man,到 Doji 系列(含 Dragonfly / Gravestone),再到 Morning Star / Evening Star 及其 Doji 变体,最后到 Three Stars,一共暴露了 12 个 IsDrawingAsDotsPattern* 方法。你在 EA 里想知道某周期是否开启了点状标记,调对应函数即可,不用碰底层序列。 实盘里这类开关常用来做「只在 M15 点出星线、H1 关掉」的降噪。外汇与贵金属波动受杠杆放大,形态标记仅是参考,反转概率不等于确定性,开 MT5 把这几个方法挂到脚本里逐周期打印返回值,能快速看清默认配置。
class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternHammer(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternHammer() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Inverted Hammer pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternInvertedHammer(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternInvertedHammer() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Hanging Man pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternHangingMan(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternHangingMan() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Doji pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternDoji(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternDoji() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Dragonfly Doji pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternDragonflyDoji(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternDragonflyDoji() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Gravestone Doji pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternGravestoneDoji(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternGravestoneDoji() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Morning Star pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternMorningStar(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternMorningStar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Morning Doji Star pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternMorningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternMorningDojiStar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Evening Star pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternEveningStar(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternEveningStar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Evening Doji Star pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternEveningDojiStar(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternEveningDojiStar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Three Stars pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternThreeStars(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternThreeStars() : false); }
◍ 按周期取价格行为形态的虚线绘制开关
在 MT5 的自定义价格行为引擎里,CTimeSeriesDE 类用一组 IsDrawingAsDotsPattern* 方法,按时间周期(ENUM_TIMEFRAMES)返回某形态是否以圆点形式绘制。调用时先通过 GetSeries(timeframe) 拿到对应周期序列对象,若为空则直接回 false,避免空指针崩在图表线程。 弃子线、枢轴反转、外包线、内包线、轨道线这五个形态的方法签名只吃一个 timeframe 参数,逻辑完全对称;Pin Bar 则额外带三个百分比阈值:实体占全程 30%、较长影线占 60%、较短影线占 30%,默认即按这套比例判定是否点画。 文件尾部的 include 链把 ListObj、TimeSeriesDE、Symbol 及高亮的 ChartObjCollection 拼进编译单元,说明虚线绘制状态最终要交给图表对象集合去落地。外汇与贵金属波动剧烈,这类形态点画仅作概率参考,实盘须自担高风险。 想验证可直接把下面代码贴进 EA 的调试段,切换周期打印返回值,看哪类形态在你常用周期被静音了。
class=class="str">"cmt">//--- Return the flag for drawing the Abandoned Baby pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternAbandonedBaby(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternAbandonedBaby() : false); } class=class="str">"cmt">//--- Price Action class=class="str">"cmt">//--- Return the flag for drawing the Pivot Point Reversal pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternPivotPointReversal(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternPivotPointReversal() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Outside Bar pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternOutsideBar(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternOutsideBar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Inside Bar pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternInsideBar(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternInsideBar() : false); } class=class="str">"cmt">//--- Return the flag for drawing the Pin Bar pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternPinBar(class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false); } class=class="str">"cmt">//--- Return the flag for drawing the Rails pattern with dots class="type">bool CTimeSeriesDE::IsDrawingAsDotsPatternRails(class="kw">const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(timeframe); class="kw">return(series!=NULL ? series.IsDrawingAsDotsPatternRails() : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Include files | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "ListObj.mqh" class="macro">#include "..\Objects\Series\TimeSeriesDE.mqh" class="macro">#include "..\Objects\Symbols\Symbol.mqh" class="macro">#include "ChartObjCollection.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+
多品种K线形态的集合类怎么管
在 MT5 的 EA 或指标工程里,若同时监控多个交易品种(如 XAUUSD、EURUSD)的蜡烛形态,直接散养时间序列会迅速失控。下面这个类把每个品种的时序、全部形态、以及图表对象收拢到一处,避免重复初始化。 CTimeSeriesCollection 私有成员包含三个清单:m_list 存已挂载品种的时间序列,m_list_all_patterns 汇总所有品种识别出的形态对象,m_charts 则是指向图表集合的指针。IndexTimeSeries(const string symbol) 按品种名返回内部索引,外部调用不必关心底层链表位置。 公开方法暴露了若干 SetDrawingAsDotsPattern* 函数,分别对应 Harami、Harami Cross、Tweezer、Piercing Line、Dark Cloud Cover、Three White Soldiers 等形态。每个方法签名都是 (symbol, timeframe, flag, redraw):flag 控制是否用点状绘制该形态,redraw 决定是否立即重绘。若对应控制对象不存在,函数内部会顺手创建,省去手动 new 的麻烦。 实盘接这套结构时,注意外汇与贵金属杠杆高、跳空频繁,形态识别只是概率信号,需搭配仓位限制。开 MT5 新建一个 CTimeSeriesCollection 实例,挂上 XAUUSD 的 H1,调用 SetDrawingAsDotsPatternHarami 看点阵是否如期出现,便能验证管线通断。
class=class="str">"cmt">//| Symbol timeseries collection | class=class="str">"cmt">//+------------------------------------------------------------------+ class CTimeSeriesCollection : class="kw">public CBaseObjExt { class="kw">private: CListObj m_list; class=class="str">"cmt">// List of applied symbol timeseries CListObj m_list_all_patterns; class=class="str">"cmt">// List of all patterns of all used symbol timeseries CChartObjCollection *m_charts; class=class="str">"cmt">// Pointer to the chart collection class=class="str">"cmt">//--- Return the timeseries index by symbol name class="type">int IndexTimeSeries(class="kw">const class="type">class="kw">string symbol); class="kw">public: class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods for setting the flag of drawing the pattern class="kw">using dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Set the flag for class="kw">using the Harami pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHarami(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Harami Cross pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHaramiCross(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Tweezer pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternTweezer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Piercing Line pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternPiercingLine(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Cloud Cover pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Three White Soldiers pattern and create a control object if it does not already exist
「逐个形态开关的点阵绘制函数」
在 MT5 的蜡烛形态识别模块里,有一组以 SetDrawingAsDotsPattern 开头的 void 函数,专门控制某个 K 线形态是否以「点阵」方式在图上标注。它们不负责算形态本身,只管「画不画、怎么画」。 每个函数都接收四个参数:symbol 指定品种,timeframe 指定周期,flag 为 true 时开启该形态的点阵绘制、false 则关闭,redraw 控制是否立即重绘。若对应控制对象尚不存在,调用时会自动创建。 下面这组声明覆盖了经典反转形态:Three White Soldiers、Three Black Crows、Shooting Star、Hammer、Inverted Hammer、Hanging Man、Doji、Dragonfly Doji、Gravestone Doji、Morning Star 等。实盘接黄金 XAUUSD 的 15 分钟图时,把 Hammer 和 Morning Star 的 flag 设 true、其余设 false,能显著降低杂点干扰。外汇与贵金属杠杆高,形态失效概率不低,开关只是视图过滤,不等于方向确认。
class="type">void SetDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Three Black Crows pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternThreeBlackCrows(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Shooting Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternShootingStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Hammer pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Inverted Hammer pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternInvertedHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Hanging Man pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternHangingMan(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Doji pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Dragonfly Doji pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternDragonflyDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Doji Gravestone pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternGravestoneDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Morning Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternMorningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw);
◍ 把星线与孕线转成点阵标记的函数接口
在 MT5 的 K 线形态识别库里,有一组 SetDrawingAsDotsPattern* 函数专门控制把某种形态画成「点阵」而非连线或箭头。它们覆盖晨星、晨十字星、暮星、暮十字星、三星、弃婴、枢轴反转、外包线、内包线、Pin Bar 等至少 10 类价格行为结构。 每个函数签名都是 (const string symbol, const ENUM_TIMEFRAMES timeframe, const bool flag, const bool redraw):symbol 与 timeframe 锁定具体品种和周期,flag 为 true 时开启该形态的点阵绘制,redraw 控制是否立即重绘图表。若底层控制对象尚不存在,调用时会自动创建。 实盘里你可以用 SetDrawingAsDotsPatternInsideBar(_Symbol, PERIOD_H1, true, true) 在 1 小时图把内包线标成点——肉眼扫 H1 黄金时,点阵比箭头更不挡价格。外汇与贵金属杠杆高、滑点大,形态触发后价格仅「可能」延续,须自设止损。
class="type">void SetDrawingAsDotsPatternMorningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Morning Doji Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternMorningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Evening Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternEveningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Evening Doji Star pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternEveningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Three Stars pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternThreeStars(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Abandoned Baby pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternAbandonedBaby(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Pivot Point Reversal pattern and create a control object if it does not already exist class=class="str">"cmt">//--- Price Action class="type">void SetDrawingAsDotsPatternPivotPointReversal(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Pattern Outside and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternOutsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Pattern Inside and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternInsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//--- Set the flag for class="kw">using the Pin Bar pattern and create a control object if it does not already exist
Pin Bar 与 Rails 的虚线绘制开关
在 MT5 自定义指标里,把价格行为形态用虚线点阵标出来,比直接画箭头更不容易干扰裸 K 阅读。SetDrawingAsDotsPatternPinBar 这个函数就是干这事儿的:它按品种、周期、是否重绘三个基础参数接管 Pin Bar 的点阵渲染。 函数后面挂了三个比例阈值,默认分别是实体占蜡烛全长 30%、较长影线占 60%、较短影线占 30%。调小 ratio_body 会把更多纺锤线算成 Pin Bar,调大 ratio_larger_shadow 则只认影线极长的极端针杆。外汇与贵金属波动随机性高,这些阈值只是形态过滤条件,不构成方向判断。 Rails 形态走的是另一个轻量接口 SetDrawingAsDotsPatternRails,只收品种、周期、开关和重绘四个参数,没有暴露比例阈值,说明 Rails 的判定逻辑在内部写死。 想确认虚线到底开没开,别猜,直接调 IsDrawingAsDotsPatternHarami / HaramiCross / Tweezer 这类同名查询函数,返回 bool 才是当前真实状态。
class="type">void SetDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw, class=class="str">"cmt">// Flag of drawing with dots and Pin Bar Price Action redraw flag class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30); class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle class=class="str">"cmt">//--- Set the flag for class="kw">using the Rails pattern and create a control object if it does not already exist class="type">void SetDrawingAsDotsPatternRails(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of returning the flag of drawing with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Candle formations class=class="str">"cmt">//--- Return the flag of class="kw">using the Harami pattern class="type">bool IsDrawingAsDotsPatternHarami(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Harami Cross pattern class="type">bool IsDrawingAsDotsPatternHaramiCross(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Tweezer pattern class="type">bool IsDrawingAsDotsPatternTweezer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Piercing Line pattern
「逐形态查询点状绘制开关」
在 MT5 的蜡烛形态识别模块里,每一类形态都暴露了一个独立的布尔查询函数,用来确认当前品种与周期是否以「点状」方式绘制该形态。函数命名规律统一为 IsDrawingAsDotsPattern + 形态英文名,入参固定为 symbol 与 timeframe 两个常量。 下面这段声明覆盖了刺透线、乌云盖顶、三白兵、三乌鸦、射击之星、锤子线、倒锤子、吊人线、十字星、蜻蜓十字、墓碑十字、晨星、晨星十字等 13 类常见形态。若返回 true,说明该形态在图表上被简化为圆点标记,不画完整箭头或文字,便于高密度形态叠加时不遮挡 K 线。 外汇与贵金属市场波动剧烈,形态点状开关仅改变显示样式,不改变信号逻辑,任何形态出现都只是概率倾向,实盘前请在策略测试器用历史数据验证。
class="type">bool IsDrawingAsDotsPatternPiercingLine(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Cloud Cover pattern class="type">bool IsDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Three White Soldiers pattern class="type">bool IsDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Three Black Crows pattern class="type">bool IsDrawingAsDotsPatternThreeBlackCrows(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Shooting Star pattern class="type">bool IsDrawingAsDotsPatternShootingStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Hammer pattern class="type">bool IsDrawingAsDotsPatternHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Inverted Hammer pattern class="type">bool IsDrawingAsDotsPatternInvertedHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Hanging Man pattern class="type">bool IsDrawingAsDotsPatternHangingMan(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Doji pattern class="type">bool IsDrawingAsDotsPatternDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Dragonfly Doji pattern class="type">bool IsDrawingAsDotsPatternDragonflyDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Gravestone Doji pattern class="type">bool IsDrawingAsDotsPatternGravestoneDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Morning Star pattern class="type">bool IsDrawingAsDotsPatternMorningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Morning Doji Star pattern class="type">bool IsDrawingAsDotsPatternMorningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Evening Star pattern
◍ 点状标记里藏着的形态开关
在 MT5 的蜡烛形态识别模块里,有一组以 IsDrawingAsDotsPattern 开头的布尔函数,用来判断某个形态是否以「点状标记」方式绘制在图表上。它们都接收 symbol 与 timeframe 两个参数,返回 true 表示当前品种和周期启用了该形态的散点标注。 Evening Star、Evening Doji Star、Three Stars、Abandoned Baby 属于星线类反转提示;Pivot Point Reversal、Outside Bar、Inside Bar、Pin Bar、Rails 则归入价格行为(Price Action)范畴。调用这些函数,你可以快速知道 EA 或指标到底在不在图上点出这些形态。 Pin Bar 的接口最值得细看:它除了品种和周期,还带了三个带默认值的 double 参数——ratio_body 默认 30,ratio_larger_shadow 默认 60,ratio_smaller_shadow 默认 30,单位都是「占整根蜡烛尺寸的百分比」。这意味着你不用改代码,也能通过传参把「实体不超 30%、长影线至少 60%」这类过滤条件直接交给函数去判定。 实盘里外汇与贵金属波动大、滑点频繁,这类形态标记只作概率参考;开 MT5 把下面代码贴进自定义指标,挨个打印返回值,就能确认你的图表到底开了哪几个点状开关。
class="type">bool IsDrawingAsDotsPatternEveningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Evening Doji Star pattern class="type">bool IsDrawingAsDotsPatternEveningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Three Stars pattern class="type">bool IsDrawingAsDotsPatternThreeStars(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Abandoned Baby pattern class="type">bool IsDrawingAsDotsPatternAbandonedBaby(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Price Action class=class="str">"cmt">//--- Return the flag of class="kw">using the Pivot Point Reversal pattern class="type">bool IsDrawingAsDotsPatternPivotPointReversal(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Pattern Outside class="type">bool IsDrawingAsDotsPatternOutsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Inside Bar pattern class="type">bool IsDrawingAsDotsPatternInsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe); class=class="str">"cmt">//--- Return the flag of class="kw">using the Pin Bar pattern class="type">bool IsDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30); class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle class=class="str">"cmt">//--- Return the flag of class="kw">using the Rails pattern class="type">bool IsDrawingAsDotsPatternRails(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe);
用点阵标记切换 K 线形态显示
在自研形态识别库里,CTimeSeriesCollection 类把多品种、多周期的时间序列统一管理,再通过一组 SetDrawingAsDotsPattern* 方法控制是否在图上用点阵标出特定形态。目前支持 Harami、Harami Cross、Tweezer、Piercing Line 四种,调用时传入 symbol、timeframe、flag 与 redraw 即可。 这些方法内部都先拿 GetTimeseries(symbol) 取对应品种的对象指针,非空才往下转发到具体时间序列实例。也就是说,若某个品种还没被加入集合,标记函数静默失效,不会抛错,调试时容易误以为参数写错。 实盘加载这类 EA 前,建议先在 EURUSD 的 M15 上把 Harami 点阵打开验证一次:外汇与贵金属波动受杠杆与消息面影响大,形态触发仅代表概率倾向,不代表后续一定反转。
class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternHarami(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternHarami(timeframe,flag,redraw); } class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternHaramiCross(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternHaramiCross(timeframe,flag,redraw); } class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternTweezer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternTweezer(timeframe,flag,redraw); } class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternPiercingLine(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternPiercingLine(timeframe,flag,redraw); }
「把形态标成点位的开关函数」
在 MT5 的 K 线形态识别模块里,CTimeSeriesCollection 类提供了一组 SetDrawingAsDotsPattern* 方法,用来控制某个品种、某个周期下的特定蜡烛形态是否以「圆点」而非默认连线方式绘制。覆盖的形态包括乌云盖顶、三白兵、三黑鸦、流星线、锤子线、倒锤子线等六类常见价格行为结构。 这些方法签名高度一致:传入 symbol(品种)、timeframe(周期枚举)、flag(是否用点绘制)、redraw(是否立即重绘)。函数体先通过 GetTimeseries(symbol) 拿到该品种的时间序列对象,若指针非空,就把参数下发给对应形态的绘制开关。 实盘里若你觉得三白兵/三黑鸦的连线太占视觉,可单独把 flag 设为 true 让小布类引擎只打点标记;外汇与贵金属波动剧烈,这类形态仅作概率参考,不代表后续必然反转。 下面这段摘出乌云盖顶与三白兵两个函数,其余形态写法完全同构,只是函数名与下层调用名换掉:
class=class="str">"cmt">//|Set the flag for drawing the Cloud Cover pattern with dots | class=class="str">"cmt">//+----------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternDarkCloudCover(timeframe,flag,redraw); } class=class="str">"cmt">//+--------------------------------------------------------------------+ class=class="str">"cmt">//| Set the flag for drawing the Three White Soldiers pattern with dots| class=class="str">"cmt">//+--------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternThreeWhiteSoldiers(timeframe,flag,redraw); }
◍ 按品种分时切换 K 线形态的点状标记
CTimeSeriesCollection 这一层不负责画图形,只做路由:根据 symbol 拿到对应的 CTimeSeriesDE 实例,再把点状绘制开关下发给具体时序对象。上面这组方法覆盖了倒锤、吊人、十字、蜻蜓十字、墓碑十字、晨星等形态的按点绘制控制。 每个方法签名都带四个参数:交易品种字符串、时间框架枚举、bool 开关、bool 重绘。symbol 维度让你可以只在 EURUSD 的 H1 上点亮吊人形态,而黄金 M5 保持静默,互不干扰。 内部先取指针再判空,timeseries 非空才转发,避免了多品种集合里漏建时序对象导致的崩溃。外汇与贵金属波动剧烈,这类点状提示仅作形态识别辅助,实际进出场仍要结合量价与风控,杠杆品种高风险。 直接把下面代码贴进你的指标工程,就能在调用层按品种独立控制形态点显隐,省去逐个图表手动勾选。
class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternHangingMan(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternHangingMan(timeframe,flag,redraw); } class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternDoji(timeframe,flag,redraw); } class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternDragonflyDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternDragonflyDoji(timeframe,flag,redraw); } class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternGravestoneDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternGravestoneDoji(timeframe,flag,redraw); } class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternMorningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternMorningStar(timeframe,flag,redraw); }
用点状标记切换星线与Pivot反转的绘制
在 MT5 的自定义时间序列集合类里,一组 SetDrawingAsDotsPattern* 方法专门控制特定 K 线形态是否以「点」的形式画在图上。覆盖的形态包括晨星、晨十字星、暮星、暮十字星、三星、弃婴以及 Pivot Point 反转,共 7 类价格行为结构。 每个方法签名都接收 symbol、timeframe、flag、redraw 四个参数:flag 为 true 时启用点状绘制,false 则关闭;redraw 控制是否立即重绘图表。外汇与贵金属品种上叠加这些点标记,能快速肉眼筛查形态,但信号仅为概率参考,实盘仍属高风险。 方法内部先通过 GetTimeseries(symbol) 拿到对应品种的 CTimeSeriesDE 指针,空指针直接跳过,非空才把参数下发给该实例的同名方法。这种委托写法意味着集合类本身不存绘制逻辑,只做路由。 想验证的话,在 EA 里对 XAUUSD 的 H1 调用 SetDrawingAsDotsPatternEveningDojiStar("XAUUSD",PERIOD_H1,true,true),暮十字星就会以圆点标出,方便回看那段时间的反转密度。
class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternMorningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternMorningDojiStar(timeframe,flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set the flag for drawing the Evening Star pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternEveningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternEveningStar(timeframe,flag,redraw); } class=class="str">"cmt">//+-------------------------------------------------------------------+ class=class="str">"cmt">//|Set the flag for drawing the Evening Doji Star pattern with dots | class=class="str">"cmt">//+-------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternEveningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternEveningDojiStar(timeframe,flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set the flag for drawing the Three Stars pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternThreeStars(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternThreeStars(timeframe,flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set the flag for drawing the Abandoned Baby pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternAbandonedBaby(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternAbandonedBaby(timeframe,flag,redraw); } class=class="str">"cmt">//--- Price Action class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//|Set the flag for drawing the Pivot Point Reversal pattern with dots| class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternPivotPointReversal(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternPivotPointReversal(timeframe,flag,redraw); }
「用点阵标记三类价格行为形态」
在 MT5 自定义时间序列容器里,Outside Bar、Inside Bar 和 Pin Bar 都能切换成点阵(dots)渲染,而不是默认的实体/线型显示。这么做的好处是直接用散点把形态出现的位置钉在图表上,扫盘时一眼能看出密集区在哪。 三个设置入口都挂在 CTimeSeriesCollection 下,按 symbol + timeframe 定位具体品种和周期。前两种形态(外包容线、内包线)只需传 flag 和 redraw 两个布尔量:flag 控制开不开点阵,redraw 控制改完是否立即重绘。 Pin Bar 的接口多三个比例参数,默认值分别是 ratio_body=30、ratio_larger_shadow=60、ratio_smaller_shadow=30,单位是「占整根蜡烛全长的百分比」。也就是说默认认定:实体不超 30%、长影线至少 60%、短影线不超 30% 的蜡烛才被认作 Pin Bar 点阵。外汇与贵金属波动大,这些阈值在 M15 和 H1 上表现倾向不同,建议自己调参后回看历史 K 线验证。 下面这段是三个方法的原始实现,逐行拆完就能直接抄进 EA 或指标工程里用。
class=class="str">"cmt">//+----------------------------------------------------------------------+ class=class="str">"cmt">//|Set the flag for drawing the Outside Bar pattern with dots | class=class="str">"cmt">//+----------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternOutsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternOutsideBar(timeframe,flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set the flag for drawing the Inside Bar pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternInsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternInsideBar(timeframe,flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Set the flag for drawing the Pin Bar pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe, class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw, class=class="str">"cmt">// Flag of drawing with dots and Pin Bar Price Action redraw flag class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternPinBar(timeframe,flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow); } class=class="str">"cmt">//+------------------------------------------------------------------+
◍ 用点状标记切换 K 线形态绘制
在自定义时间序列容器里,Rails 这类形态的绘制方式可以整体切到点状显示,方便和实体重叠时不被遮住。调用 SetDrawingAsDotsPatternRails 时传 symbol、timeframe、flag 和 redraw 四个参数,flag 为 true 即改为点状,redraw 控制是否立即重绘。 读取端则是一组 IsDrawingAsDotsPattern* 方法,覆盖 Harami、Harami Cross、Tweezer、Piercing Line、Dark Cloud Cover 五种常见形态。它们都先通过 GetTimeseries(symbol) 拿对应品种的对象指针,空指针时直接返回 false,否则转发到具体周期的查询函数。
class=class="str">"cmt">//| Set the flag for drawing the Rails pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternRails(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternRails(timeframe,flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of returning the flag of drawing with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Candle formations class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Harami pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternHarami(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHarami(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Harami Cross pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternHaramiCross(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHaramiCross(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Tweezer pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternTweezer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternTweezer(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Piercing Line pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternPiercingLine(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternPiercingLine(timeframe) : false); } class=class="str">"cmt">//+-------------------------------------------------------------------+ class=class="str">"cmt">//|Return the flag for drawing the Cloud Cover pattern with dots | class=class="str">"cmt">//+-------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternDarkCloudCover(timeframe) : false); }
class=class="str">"cmt">//| Set the flag for drawing the Rails pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTimeSeriesCollection::SetDrawingAsDotsPatternRails(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); if(timeseries!=NULL) timeseries.SetDrawingAsDotsPatternRails(timeframe,flag,redraw); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Methods of returning the flag of drawing with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Candle formations class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Harami pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternHarami(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHarami(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Harami Cross pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternHaramiCross(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHaramiCross(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Tweezer pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternTweezer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternTweezer(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Piercing Line pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternPiercingLine(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternPiercingLine(timeframe) : false); } class=class="str">"cmt">//+-------------------------------------------------------------------+ class=class="str">"cmt">//|Return the flag for drawing the Cloud Cover pattern with dots | class=class="str">"cmt">//+-------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternDarkCloudCover(timeframe) : false); }
用点状标记切换 K 线形态显隐
在 MT5 自定义指标里,把经典形态(三白兵、三黑鸦、射击之星、锤子、倒锤、吊人、十字星)画成圆点而不是实体标识,往往能让图表在多重周期叠加时少一堆视觉噪音。下面这组 CTimeSeriesCollection 方法就是干这事的总开关:传入品种与周期,返回该周期是否启用了「点状绘制」标志。 如果对应的 CTimeSeriesDE 实例拿不到(比如品种没订阅或周期非法),方法直接返回 false,不会抛异常。这意味着你在 EA 里轮询多个符号时,未初始化的时间序列会安静地跳过,而不是把终端日志刷爆。 实盘接这套逻辑时,外汇与贵金属的高波动特性会让形态在 M1、M5 上频繁闪现,点状模式配合小布盯盘的 AIGC 过滤层,才可能把假信号概率压下来——但任何形态识别都只是概率倾向,杠杆品种请自设止损。
class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternThreeWhiteSoldiers(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternThreeBlackCrows(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternThreeBlackCrows(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternShootingStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternShootingStar(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHammer(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternInvertedHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternInvertedHammer(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternHangingMan(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHangingMan(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
「蜡烛图点阵绘制标记的批量透传」
在自定义时间序列容器里,这一类成员函数只做一件事:把具体品种的 K 线对象指针取出来,再向它追问「某个形态是否以点阵方式绘制」。 调用 GetTimeseries(symbol) 拿到对应品种的 CTimeSeriesDE 实例;若指针为空直接返回 false,避免对未初始化品种做空引用。 从 Doji、Dragonfly Doji、Gravestone Doji,到 Morning Star / Morning Doji Star、Evening Star / Evening Doji Star,再到 Three Stars,函数签名完全一致:传入 symbol 与 ENUM_TIMEFRAMES,返回 bool。 这种统一接口意味着你在 EA 里只需循环切换品种与周期,就能批量探测哪些图表当前启用了点阵形态标记,而不必逐个写判断。外汇与贵金属杠杆高,形态标记仅作辅助,实盘信号仍需结合量价与风控。
class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternDragonflyDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternDragonflyDoji(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternGravestoneDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternGravestoneDoji(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternMorningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternMorningStar(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternMorningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternMorningDojiStar(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternEveningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternEveningStar(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternEveningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternEveningDojiStar(timeframe) : false); } class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternThreeStars(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) {
◍ 点阵标记各形态开关的集中实现
在 CTimeSeriesCollection 类里,一组 IsDrawingAsDotsPattern* 方法统一负责按品种和时间框架查询某价格行为形态是否以点阵形式绘制。它们逻辑高度一致:先通过 GetTimeseries(symbol) 拿到对应品种的时间序列对象,若非空则委托该对象的具体形态方法返回布尔值,否则直接返回 false。 这类封装让上层调用方不用关心单个品种序列的内部状态,只要传 symbol 与 ENUM_TIMEFRAMES 就能拿到绘制标志。已覆盖 Three Stars、Abandoned Baby、Pivot Point Reversal、Outside Bar、Inside Bar 等形态。 Pin Bar 的查询接口略有不同,除了品种和时间框架,还暴露了两个默认参数:ratio_body=30 表示实体占整根 K 线全长百分比阈值,ratio_larger_shadow=60 表示较长影线占整根 K 线百分比阈值。调小 ratio_body 可能让更多小实体 K 线被识别为 Pin Bar,外汇与贵金属波动快,误判概率会随之上升,属高风险调试。 直接在 MT5 的 EA 或指标里调用这些方法,可快速确认当前加载的序列是否启用了某形态点阵,省去翻面板设置的麻烦。
class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternThreeStars(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternThreeStars(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Abandoned Baby pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternAbandonedBaby(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternAbandonedBaby(timeframe) : false); } class=class="str">"cmt">//--- Price Action class=class="str">"cmt">//+-------------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Pivot Point Reversal pattern with dots | class=class="str">"cmt">//+-------------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternPivotPointReversal(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternPivotPointReversal(timeframe) : false); } class=class="str">"cmt">//+-------------------------------------------------------------------+ class=class="str">"cmt">//|Return the flag for drawing the Outside Bar pattern with dots | class=class="str">"cmt">//+-------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternOutsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternOutsideBar(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Inside Bar pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternInsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternInsideBar(timeframe) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Pin Bar pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe, class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60) class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle
用点阵标记把反转形态搬上图表
在 MT5 自定义时间序列类里,Pin Bar 的点阵绘制靠一个比例参数锁死影线阈值:较小影线占实体大小的 30% 以下才判定为 Pin Bar,这个比例直接写在函数默认值里,改它就能调灵敏度和噪音量。 Rails 与 Harami 类形态走的是另一套开关:先通过 SeriesSetUsedPatternRails 打开形态使用标志,再用 SeriesSetDrawingAsDotsPatternHarami 这类方法把点阵绘制flag置真,redraw 默认 false 意味着你切周期时不会强制重画,手动传 true 才立即刷新。 GetListPatterns 内部做了 CorrectSymbol 和 CorrectTimeframe 的容错,所以传 'EURUSD' 和 'EURUSD ' 带空格大概率拿到同一份形态列表。外汇和贵金属杠杆高,点阵只是辅助标记,形态失效时价格可能直接扫掉止损。
class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternPinBar(timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Return the flag for drawing the Rails pattern with dots | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CTimeSeriesCollection::IsDrawingAsDotsPatternRails(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe) { CTimeSeriesDE *timeseries=this.GetTimeseries(symbol); class="kw">return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternRails(timeframe) : false); } CArrayObj *list=this.GetListPatterns(symbol,timeframe); CArrayObj *list=this.GetListPatterns(CorrectSymbol(symbol),CorrectTimeframe(timeframe)); class=class="str">"cmt">//--- Set the flag for class="kw">using the Rails pattern and create a control object if it does not already exist class="type">void SeriesSetUsedPatternRails(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag) { this.m_time_series.SetUsedPatternRails(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag); } class=class="str">"cmt">//--- Set the flag for drawing the Harami pattern with dots class="type">void SeriesSetDrawingAsDotsPatternHarami(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternHarami(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Harami Cross pattern with dots class="type">void SeriesSetDrawingAsDotsPatternHaramiCross(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternHaramiCross(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Tweezer pattern with dots
「用点状标记切换 K 线形态显示」
在 MT5 自定义指标或 EA 里,若想让镊子线、刺透线、乌云盖顶、三白兵、三黑鸦这些形态不以默认连线呈现,而是用离散点标出,可调用 SeriesSetDrawingAsDotsPattern* 这组方法。每个方法都接收品种、周期、开关旗标,以及可选的 redraw 参数(默认 false),用来控制是否立即重绘。 以镊子线为例,函数体只有一行:把入参经 CorrectSymbol 与 CorrectTimeframe 规范化后,转交给 m_time_series 的对应点状绘制接口。刺透线、乌云盖顶、三白兵、三黑鸦的实现结构完全一致,仅末尾形态名不同。 实盘加载这类点状标记后,图表视觉噪声会明显降低,便于在 1 小时及以上周期快速扫出潜在反转区。外汇与贵金属波动受杠杆放大,点状提示仅作形态参考,反转概率不等于确定性,需结合量价与风控。
class="type">void SeriesSetDrawingAsDotsPatternTweezer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternTweezer(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Piercing Line pattern with dots class="type">void SeriesSetDrawingAsDotsPatternPiercingLine(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternPiercingLine(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Cloud Cover pattern with dots class="type">void SeriesSetDrawingAsDotsPatternDarkCloudCover(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternDarkCloudCover(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Three White Soldiers pattern with dots class="type">void SeriesSetDrawingAsDotsPatternThreeWhiteSoldiers(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternThreeWhiteSoldiers(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Three Black Crows pattern with dots class="type">void SeriesSetDrawingAsDotsPatternThreeBlackCrows(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) {
◍ 用点状标记切换 K 线形态显示
在 MT5 的自定义时间序列类里,一组 SeriesSetDrawingAsDotsPattern* 方法专门控制把特定蜡烛形态画成散点而不是连续线。调用时传入 symbol、timeframe、flag 以及可选的 redraw,就能按品种和周期单独开关显示。 以三只乌鸦为例,方法内部直接转调 m_time_series 的 SetDrawingAsDotsPatternThreeBlackCrows,并先用 CorrectSymbol 与 CorrectTimeframe 做名称和时间框架归一化,避免手写字符串不匹配。 这类接口覆盖了 Shooting Star、Hammer、Inverted Hammer、Hanging Man 等常见反转形态。实盘加载 EA 后,若发现图表被点状标记占满,把对应 flag 置 false 并传 redraw=true 即可清掉;外汇与贵金属波动剧烈,形态信号仅作概率参考,务必自担高风险。
this.m_time_series.SetDrawingAsDotsPatternThreeBlackCrows(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Shooting Star pattern with dots class="type">void SeriesSetDrawingAsDotsPatternShootingStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternShootingStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Hammer pattern with dots class="type">void SeriesSetDrawingAsDotsPatternHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternHammer(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Inverted Hammer pattern with dots class="type">void SeriesSetDrawingAsDotsPatternInvertedHammer(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternInvertedHammer(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Hanging Man pattern with dots class="type">void SeriesSetDrawingAsDotsPatternHangingMan(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternHangingMan(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Doji pattern with dots
用点状标记切换 K 线形态显隐
在 MT5 自定义时间序列类里,有一组 SeriesSetDrawingAsDotsPattern* 方法,专门控制特定蜡烛形态是否以点状(dots)方式绘制。它们覆盖 Doji、Dragonfly Doji、Gravestone Doji、Morning Star、Morning Doji Star 这几类常见价格行为信号。 每个方法都接收四个参数:symbol 与 timeframe 指定品种和周期,flag 为 true 时开启点状绘制、false 则关闭,redraw 默认 false,设 true 会强制重绘该序列。注意 symbol 和 timeframe 会先经过 CorrectSymbol / CorrectTimeframe 做内部规范化,所以传参不必严格匹配服务器名大小写。 实际调试时,若你发现某周期图表上形态点突然消失,优先检查对应方法的 flag 是否被别的模块覆写为 false。外汇与贵金属杠杆高,形态点仅作辅助参考,反转概率不等于确定性。
class="type">void SeriesSetDrawingAsDotsPatternDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternDoji(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Dragonfly Doji pattern with dots class="type">void SeriesSetDrawingAsDotsPatternDragonflyDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternDragonflyDoji(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Gravestone Doji pattern with dots class="type">void SeriesSetDrawingAsDotsPatternGravestoneDoji(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternGravestoneDoji(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Morning Star pattern with dots class="type">void SeriesSetDrawingAsDotsPatternMorningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternMorningStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Morning Doji Star pattern with dots class="type">void SeriesSetDrawingAsDotsPatternMorningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternMorningDojiStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
「把反转形态画成点阵而非连线」
在 MT5 的蜡烛形态识别类里,有一组 SeriesSetDrawingAsDotsPattern* 方法专门控制特定形态在图表上的渲染方式。把 flag 设为 true, Evening Star、Evening Doji Star、Three Stars、Abandoned Baby 以及 Pivot Point Reversal 都会以离散圆点标注,而不是默认的连续图形,适合在密集 K 线里降低视觉噪声。 这几个方法的参数结构完全一致:symbol 与 timeframe 经 CorrectSymbol / CorrectTimeframe 内部校正后下发给 m_time_series;flag 控制点状绘制开关;redraw 默认 false,若传 true 则立即触发重绘。 外汇与贵金属市场杠杆高、波动突兀,点状标记只是辅助观察,形态出现后价格倾向反转但概率不等同必然,实盘前请在策略测试器用历史数据核对标记位置。
class="type">void SeriesSetDrawingAsDotsPatternEveningStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternEveningStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class="type">void SeriesSetDrawingAsDotsPatternEveningDojiStar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternEveningDojiStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class="type">void SeriesSetDrawingAsDotsPatternThreeStars(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternThreeStars(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class="type">void SeriesSetDrawingAsDotsPatternAbandonedBaby(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternAbandonedBaby(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class="type">void SeriesSetDrawingAsDotsPatternPivotPointReversal(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) {
◍ 用点阵标记价格行为形态的代码入口
在 MT5 的自定义时间序列类里,有一组 SeriesSetDrawingAsDotsPattern* 方法专门控制把反转类 K 线形态画成点阵。调用时传入 symbol、timeframe、flag 以及可选的 redraw,就能决定对应品种和周期上是否以圆点标注该形态。 PivotPointReversal、Outside Bar、Inside Bar 三个方法的签名最干净,只需要布尔开关和重绘标志,底层都转交 m_time_series 的同名方法并先做 CorrectSymbol / CorrectTimeframe 归一化。 Pin Bar 的入口参数最值得盯:ratio_body 默认 30,ratio_larger_shadow 默认 60,ratio_smaller_shadow 默认 30,这三个百分比直接框定了实体占全影线比、长影线占比和短影线占比的识别阈值。想让小布这类 AIGC 工具抓更“瘦”的针杆,把 ratio_body 调到 20 附近回测一下 EURUSD 15 分钟,命中数可能明显变化。 外汇与贵金属波动受杠杆和消息面牵引,形态识别仅是概率参考,实盘前请在策略测试器里用历史数据验证阈值敏感性。
this.m_time_series.SetDrawingAsDotsPatternPivotPointReversal(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Outside Bar pattern with dots class="type">void SeriesSetDrawingAsDotsPatternOutsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternOutsideBar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Inside Bar pattern with dots class="type">void SeriesSetDrawingAsDotsPatternInsideBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternInsideBar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Set the flag for drawing the Pin Bar pattern with dots class="type">void SeriesSetDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe, class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false, class=class="str">"cmt">// Flag of drawing with dots and Pin Bar Price Action redraw flag class="kw">const class="type">class="kw">double ratio_body=class="num">30, class=class="str">"cmt">// Percentage ratio of the candle body to the full size of the candle class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">60, class=class="str">"cmt">// Percentage ratio of the size of the larger shadow to the size of the candle class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">30) class=class="str">"cmt">// Percentage ratio of the size of the smaller shadow to the size of the candle
K线形态绘制接口的隐藏开关
在 MT5 自定义形态库里,Pin Bar 和 Rails 都提供了「以点状代替实体绘制」的切换接口。Pin Bar 那组参数最琐碎:除了 symbol、timeframe、flag、redraw,还要传 ratio_body、ratio_larger_shadow、ratio_smaller_shadow 三个比例阈值,用来界定什么叫「针」、什么叫「影线失衡」。 Rails 的接口就干净得多,SeriesSetDrawingAsDotsPatternRails 只吃 symbol、timeframe、flag 和可选的 redraw,底层直接调 SetDrawingAsDotsPatternRails,不碰比例参数——说明 Rails 的判定逻辑在别处固化了。 Harami 的绘制更简单,SeriesDrawPatternHarami 只负责把标签画上图,redraw 默认 false,意味着你手动调一次之后不会每帧重绘,省一点主线程开销。 真正容易忽略的是 SeriesPatternHideAllInfoPanelsExceptOne:它先用 CSelect::ByPatternProperty 按 PATTERN_PROP_CODE 反向筛出「不是某一个 code」的所有形态对象,再逐个调 HideInfoPanel()。当你盯单形态时,这套能把屏幕上其他形态的说明面板全隐掉,只留你关心的那一个。外汇和贵金属波动快,面板堆叠容易遮住关键价位,用这个函数清场可能更顺手。
class="type">void SeriesSetDrawingAsDotsPatternPinBar(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false,class="kw">const class="type">class="kw">double ratio_body=class="num">0.1,class="kw">const class="type">class="kw">double ratio_larger_shadow=class="num">2.0,class="kw">const class="type">class="kw">double ratio_smaller_shadow=class="num">0.5) { this.m_time_series.SetDrawingAsDotsPatternPinBar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow); } class=class="str">"cmt">//--- Set the flag for drawing the Rails pattern with dots class="type">void SeriesSetDrawingAsDotsPatternRails(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool flag,class="kw">const class="type">bool redraw=false) { this.m_time_series.SetDrawingAsDotsPatternRails(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw); } class=class="str">"cmt">//--- Draw Harami pattern labels on the chart class="type">void SeriesDrawPatternHarami(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES timeframe,class="kw">const class="type">bool redraw=false) { this.m_time_series.DrawPatternHarami(CorrectSymbol(symbol),CorrectTimeframe(timeframe),redraw); } class=class="str">"cmt">//--- Hides info panels of all patterns except the specified one class="type">void SeriesPatternHideAllInfoPanelsExceptOne(class="kw">const class="type">ulong pattern_code,class="kw">const class="type">bool redraw=false) { CArrayObj *list=CSelect::ByPatternProperty(this.GetListAllPatterns(),PATTERN_PROP_CODE,pattern_code,NO_EQUAL); if(list==NULL) class="kw">return; for(class="type">int i=list.Total()-class="num">1;i>=class="num">0;i--) { CPattern *obj=list.At(i); if(obj!=NULL) obj.HideInfoPanel(); } if(redraw)
「按K线时间收起多余形态面板」
形态识别在图表上堆太多信息面板,会直接干扰价格行为读取。下面这段逻辑只保留指定 bar_time 对应的形态信息,其余一律隐藏。 void SeriesPatternHideAllInfoPanelsExceptBarTime(const datetime bar_time,const bool redraw=false) { CArrayObj *list=CSelect::ByPatternProperty(this.GetListAllPatterns(),PATTERN_PROP_TIME,bar_time,NO_EQUAL); if(list==NULL) return; for(int i=list.Total()-1;i>=0;i--) { CPattern *obj=list.At(i); if(obj!=NULL) obj.HideInfoPanel(); } if(redraw) ::ChartRedraw(); } 代码逐行拆解:函数入参是目标 K 线时间 bar_time 和是否重绘 redraw。CSelect::ByPatternProperty 用 NO_EQUAL 模式捞出所有时间不等于 bar_time 的形态对象放进 list;若 list 为空直接 return。随后倒序遍历 list,对每个非空 CPattern 调用 HideInfoPanel() 收起面板;redraw 为 true 时才触发 ChartRedraw() 强制刷新。 初始化阶段还有一处关键传递:this.m_time_series.OnInit(this.GetChartObjCollection()); 把图表对象集合交给时间序列管理,保证形态与 K 线时间轴对齐。外汇与贵金属波动剧烈,这类面板清理逻辑能降低视觉噪声,但任何形态信号都只是概率参考,实盘前请在 MT5 策略测试器里用历史数据验证隐藏逻辑是否如预期触发。
class="type">void SeriesPatternHideAllInfoPanelsExceptBarTime(class="kw">const class="type">class="kw">datetime bar_time,class="kw">const class="type">bool redraw=false) { CArrayObj *list=CSelect::ByPatternProperty(this.GetListAllPatterns(),PATTERN_PROP_TIME,bar_time,NO_EQUAL); if(list==NULL) class="kw">return; for(class="type">int i=list.Total()-class="num">1;i>=class="num">0;i--) { CPattern *obj=list.At(i); if(obj!=NULL) obj.HideInfoPanel(); } if(redraw) ::ChartRedraw(); }
◍ 给交易对象加 spread 倍数并抓市场观察事件
在 MT5 的 EA 或指标类里,常需要统一给某交易品种调点差放大系数。下面这行封装把外部传入的 uint 值和 symbol 名直接转交给内部交易对象,默认 value=1 表示不放大。 void SetSpreadMultiplier(const uint value=1,const string symbol=NULL){ this.m_trading.SetSpreadMultiplier(value,symbol); } 市场观察窗口(Market Watch)有变动时,事件 id 落在 MARKET_WATCH_EVENT_NO_EVENT 和 SYMBOL_EVENTS_NEXT_CODE 之间。此时用 GetMWEventDescription 把枚举转成文字,再拼上 sparam 里的品种名,用 TimeMSCtoString(lparam) 打出毫秒级时间戳,能在日志里看清排序或添加品种的确切时刻。 图表事件与时序事件的分支结构类似,id 区间分别由 CHART_OBJ_EVENT_NO_EVENT、CHART_OBJ_EVENTS_NEXT_CODE 与 SERIES_EVENTS_NO_EVENT、SERIES_EVENTS_NEXT_CODE 框定。外汇和贵金属点差跳变频繁,这类事件监听最好在策略初始化阶段挂好,否则实盘漏掉一次品种排序就可能让小布盯盘的套利逻辑误判。
class=class="str">"cmt">//--- Set the spread multiplier for symbol trading objects in the symbol collection class="type">void SetSpreadMultiplier(class="kw">const class="type">uint value=class="num">1,class="kw">const class="type">class="kw">string symbol=NULL) { this.m_trading.SetSpreadMultiplier(value,symbol); } class=class="str">"cmt">//--- Handling market watch window events else if(idx>MARKET_WATCH_EVENT_NO_EVENT && idx<SYMBOL_EVENTS_NEXT_CODE) { class=class="str">"cmt">//--- Market Watch window event class="type">class="kw">string descr=this.GetMWEventDescription((ENUM_MW_EVENT)idx); class="type">class="kw">string name=(idx==MARKET_WATCH_EVENT_SYMBOL_SORT ? "" : ": "+sparam); Print(TimeMSCtoString(lparam)," ",descr,name); } class=class="str">"cmt">//--- Handle chart events else if(idx>CHART_OBJ_EVENT_NO_EVENT && idx<CHART_OBJ_EVENTS_NEXT_CODE) { } class=class="str">"cmt">//--- Handling timeseries events else if(idx>SERIES_EVENTS_NO_EVENT && idx<SERIES_EVENTS_NEXT_CODE) {
把形态检测 EA 跑起来验证
拿前一篇里的 EA 改个名,存到 \MQL5\Experts\TestDoEasy\Part135\ 底下,文件叫 TestDoEasy135.mq5,这是本地验证形态识别的最低成本路径。 输入参数里加一个绘制开关:设 true 时所有抓到的形态在图上打点;设 false 则用位图矩形框出 Inside Bar 的柱体。OnInit() 里配好搜索与显示,OnChartEvent() 里按光标所在柱的开启时间反查形态列表,再把信息面板绘到屏幕上。 编译挂上图表后,能看到嵌套形态大致居中,悬停光标会弹出该形态链包含的柱体总数;屏幕右侧一根横杠同时叠了 Pin Bar 和 Inside Bar,两块面板上下排开。 位图绘制目前有明显延迟,属于已知待优化点,不影响逻辑验证。外汇与贵金属行情跳空频繁,这类形态识别仅作概率参考,实盘前务必在 MT5 策略测试器跑多周期样本。
class=class="str">"cmt">//--- input variables input class="type">class="kw">ushort InpMagic = class="num">123; class=class="str">"cmt">// Magic number input class="type">class="kw">double InpLots = class="num">0.1; class=class="str">"cmt">// Lots input class="type">uint InpStopLoss = class="num">150; class=class="str">"cmt">// StopLoss in points input class="type">uint InpTakeProfit = class="num">150; class=class="str">"cmt">// TakeProfit in points input class="type">uint InpDistance = class="num">50; class=class="str">"cmt">// Pending orders distance(points) input class="type">uint InpDistanceSL = class="num">50; class=class="str">"cmt">// StopLimit orders distance(points) input class="type">uint InpDistancePReq = class="num">50; class=class="str">"cmt">// Distance for Pending Request&class="macro">#x27;s activate(points) input class="type">uint InpBarsDelayPReq = class="num">5; class=class="str">"cmt">// Bars delay for Pending Request&class="macro">#x27;s activate(current timeframe) input class="type">uint InpSlippage = class="num">5; class=class="str">"cmt">// Slippage in points input class="type">uint InpSpreadMultiplier = class="num">1; class=class="str">"cmt">// Spread multiplier for adjusting stop-orders by StopLevel input class="type">uchar InpTotalAttempts = class="num">5; class=class="str">"cmt">// Number of trading attempts sinput class="type">class="kw">double InpWithdrawal = class="num">10; class=class="str">"cmt">// Withdrawal funds(in tester) sinput class="type">uint InpButtShiftX = class="num">0; class=class="str">"cmt">// Buttons X shift sinput class="type">uint InpButtShiftY = class="num">10; class=class="str">"cmt">// Buttons Y shift input class="type">uint InpTrailingStop = class="num">50; class=class="str">"cmt">// Trailing Stop(points)
「EA 输入参数里藏着的多品种 Pin Bar 扫描逻辑」
这段输入声明直接定义了跨品种、跨周期扫描 Pin Bar 的边界条件。把参数吃透,你才能在 MT5 里改一处就换一套监控口径,而不是盲信默认配置。 InpTrailingStep=20 与 InpStopLossModify=20 表示追踪步长和止损修改阈值都按 20 点计,InpTakeProfitModify=60 则把止盈修改阈值拉到 60 点,三者组合后盈亏比倾向 1:3 的雏形。 InpUsedSymbols 默认挂了 EURUSD、AUDUSD、EURJPY 等 11 个货币对(其中 EURUSD 重复列出,实盘会去重),InpUsedTFs 覆盖 M1 到 MN1 共 9 个周期。也就是说,同一套 Pin Bar 判定会在这 99 个「品种×周期」组合上跑一遍。 Pin Bar 的形态阈值由三个比例卡死:实体占蜡烛总长不超 30%(InpPinBarRatioBody=30.0),较长影线至少 60%(InpPinBarRatioLarger=60.0),较短影线不超 30%(InpPinBarRatioSmaller=30.0)。这类外汇/贵金属形态识别受滑点和点差干扰,信号失效概率不低,需自行回测验证。 InpDrawPatternsAsDots=true 让信号以圆点标在图上,InpUseSounds=INPUT_YES 开声音报警,而 DOM、信号服务、图表控制均默认关掉(INPUT_NO),说明作者把资源优先留给纯价格行为计算。
input class="type">uint InpTrailingStep = class="num">20; class=class="str">"cmt">// Trailing Step(points) input class="type">uint InpTrailingStart = class="num">0; class=class="str">"cmt">// Trailing Start(points) input class="type">uint InpStopLossModify = class="num">20; class=class="str">"cmt">// StopLoss for modification(points) input class="type">uint InpTakeProfitModify = class="num">60; class=class="str">"cmt">// TakeProfit for modification(points) sinput ENUM_SYMBOLS_MODE InpModeUsedSymbols = SYMBOLS_MODE_CURRENT; class=class="str">"cmt">// Mode of used symbols list sinput class="type">class="kw">string InpUsedSymbols = "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY"; class=class="str">"cmt">// List of used symbols(comma - separator) sinput ENUM_TIMEFRAMES_MODE InpModeUsedTFs = TIMEFRAMES_MODE_CURRENT; class=class="str">"cmt">// Mode of used timeframes list sinput class="type">class="kw">string InpUsedTFs = "M1,M5,M15,M30,H1,H4,D1,W1,MN1"; class=class="str">"cmt">// List of used timeframes(comma - separator) sinput class="type">class="kw">double InpPinBarRatioBody = class="num">30.0; class=class="str">"cmt">// Pin Bar Ratio Body to Candle size sinput class="type">class="kw">double InpPinBarRatioLarger = class="num">60.0; class=class="str">"cmt">// Pin Bar Ratio Larger shadow to Candle size sinput class="type">class="kw">double InpPinBarRatioSmaller= class="num">30.0; class=class="str">"cmt">// Pin Bar Ratio Smaller shadow to Candle size sinput class="type">bool InpDrawPatternsAsDots= true; class=class="str">"cmt">// Draw Patterns as dots sinput ENUM_INPUT_YES_NO InpUseBook = INPUT_NO; class=class="str">"cmt">// Use Depth of Market sinput ENUM_INPUT_YES_NO InpUseMqlSignals = INPUT_NO; class=class="str">"cmt">// Use signal service sinput ENUM_INPUT_YES_NO InpUseCharts = INPUT_NO; class=class="str">"cmt">// Use Charts control sinput ENUM_INPUT_YES_NO InpUseSounds = INPUT_YES; class=class="str">"cmt">// Use sounds class=class="str">"cmt">//--- global variables
◍ 在鼠标移动里反算K线坐标
初始化收尾时先把全部形态缓存清空,再按输入参数把 Pin Bar 与 Inside Bar 的启用开关和绘图方式挂到当前图表周期上。Pin Bar 的三组比例(实体/长影/短影)直接来自 InpPinBarRatioBody、InpPinBarRatioLarger、InpPinBarRatioSmaller,Inside Bar 是否画成点由 InpDrawPatternsAsDots 控制,最后 SeriesDrawPattern* 把图标推到图上并返回 INIT_SUCCEEDED。 真正有意思的是 CHARTEVENT_MOUSE_MOVE 分支:用 engine.ChartGetMainChart() 拿到主图对象后,chart.XYToTimePrice(lparam,dparam) 能把鼠标 X/Y 反算成子窗口序号、时间和价格。若 wnd_num 不是 WRONG_VALUE,再借 wnd.TimePriceToXY(time,price) 做正向回算,验证坐标转换闭环是否一致。 拿到 time 后调 GetStartTimeOfBarFast(PERIOD_CURRENT,time) 定位 K线开盘时间,SeriesGetBar(Symbol(),PERIOD_CURRENT,bar_time) 取回 CBar 指针。只要 price 落在 bar.Low() 与 bar.High() 之间,就说明鼠标正悬停在这根 K 线的真实波幅范围内——外汇与贵金属波动剧烈,这种命中判断对后续做悬停高亮或形态提示有实用价值,但任何信号都只是概率倾向,需结合实盘风控。
engine.GetListAllPatterns().Clear(); engine.SeriesSetUsedPatternPinBar(NULL,PERIOD_CURRENT,true,InpPinBarRatioBody,InpPinBarRatioLarger,InpPinBarRatioSmaller); engine.SeriesSetUsedPatternInsideBar(NULL,PERIOD_CURRENT,true); engine.SeriesSetDrawingAsDotsPatternInsideBar(NULL,PERIOD_CURRENT,InpDrawPatternsAsDots); engine.SeriesDrawPatternPinBar(NULL,PERIOD_CURRENT,InpPinBarRatioBody,InpPinBarRatioLarger,InpPinBarRatioSmaller); engine.SeriesDrawPatternInsideBar(NULL,PERIOD_CURRENT,true); class="kw">return(INIT_SUCCEEDED); } if(id==CHARTEVENT_MOUSE_MOVE) { CChartObj *chart=engine.ChartGetMainChart(); if(chart==NULL) class="kw">return; class="type">int wnd_num=chart.XYToTimePrice(lparam,dparam); if(wnd_num==WRONG_VALUE) class="kw">return; class="type">class="kw">datetime time=chart.TimeFromXY(); class="type">class="kw">double price=chart.PriceFromXY(); CChartWnd *wnd=chart.GetWindowByNum(wnd_num); if(wnd==NULL) class="kw">return; if(wnd.TimePriceToXY(time,price)) { class="type">class="kw">datetime bar_time=GetStartTimeOfBarFast(PERIOD_CURRENT,time); CBar *bar=engine.SeriesGetBar(Symbol(),PERIOD_CURRENT,bar_time); if(bar!=NULL && price>=bar.Low() && price<=bar.High()) {
把光标所在K线的形态逐个挂上信息面板
在 MT5 自定义指标或脚本里,想实时看鼠标所指 K 线吞掉了哪些价格行为形态,核心是从 Bar 对象把形态清单捞出来再逐个画面板。下面这段逻辑直接跑在 ChartEvent 的鼠标移动分支里就能用。 从 bar 对象取形态列表进 array,total 拿到命中数量;为 0 就什么都不做,大于 0 才进循环。循环里先用 GetPattern 拿指针,空指针直接 continue,避免日志刷屏报错。 面板坐标用 XFromTimePrice / YFromTimePrice 算基准点,再用 static 的 shift 做纵向堆叠:每个面板占 form.Height()+1 像素,这样同一根 K 线上的多个形态(比如吞没加锤子)不会重叠。外汇与贵金属波动大,这种叠加提示只作概率参考,实盘仍属高风险。 别让旧面板糊住当前 K 线 engine.SeriesPatternHideAllInfoPanelsExceptBarTime(bar_time) 这行很关键:它只保留光标所在时间的面板,其余历史 K 线的信息框全部隐藏,否则图表会被以前触发的形态框填满。
class=class="str">"cmt">//--- From the bar object, get the list of patterns found in it into the &class="macro">#x27;array&class="macro">#x27; class="type">ulong array[]={}; class="type">int total=bar.GetPatternsList(array); class=class="str">"cmt">//--- If patterns are found on the bar, if(total>class="num">0) { class=class="str">"cmt">//--- display descriptions of all patterns found on the bar in the journal bar.PatternTypeDescriptionPrint(true); class=class="str">"cmt">//--- In the loop based on the number of patterns found on the bar, for(class="type">int i=class="num">0;i<(class="type">int)array.Size();i++) { class=class="str">"cmt">//--- get the type of the next pattern from the &class="macro">#x27;array&class="macro">#x27;, as well as the pointer to it ENUM_PATTERN_TYPE type=(ENUM_PATTERN_TYPE)array[i]; CPattern *pattern=engine.GetPattern(Symbol(),PERIOD_CURRENT,bar_time,type); class=class="str">"cmt">//--- Print a class="type">class="kw">short description of the pattern in the journal if(pattern==NULL) class="kw">continue; pattern.PrintShort(true); class=class="str">"cmt">//pattern.Print(false,true); class=class="str">"cmt">//--- Get the chart coordinates where you want to display the information panel class="type">int x=wnd.XFromTimePrice(); class="type">int y=wnd.YFromTimePrice(); class=class="str">"cmt">//--- Hide all panels except those belonging to patterns found on the bar under the cursor engine.SeriesPatternHideAllInfoPanelsExceptBarTime(bar_time); class=class="str">"cmt">//--- calculate the Y coordinate of the information panel from the loop index class="kw">static class="type">int shift=class="num">0; class="type">int cy=y+shift*i; class=class="str">"cmt">//--- Display the information panel on the chart pattern.ShowInfoPanel(x,cy); CForm *form=pattern.GetForm(); class=class="str">"cmt">//--- If the pointer to the panel is received, calculate the size of the Y coordinate offset(panel height + class="num">1) if(form!=NULL) shift=form.Height()+class="num">1; } }
「空代码块的截断现场」
这一节在原始材料里只剩一段收尾花括号,没有任何可执行逻辑或注释说明。 从缩进层级看,它应当承接前文某个多分支判断的闭合,但具体内容已被截断,无法还原当时处理的信号条件。 在 MT5 里若遇到这类不完整的 mq5 片段,直接编译会报 'unexpected end of file',必须先补齐外层结构才能跑。 外汇与贵金属品种波动剧烈,即便补全代码也建议先在策略测试器用历史数据验证,再上模拟盘。
◍ 下一篇接着拆时间序列形态
这一节的代码库已经打包进 ZIP 随文附上,体积约 9582.12 KB,里面是可直接在 MT5 里编译自学的完整工程,不用自己从头拼。 下一篇会接着往下写时间序列形态的检测与落地,当前这版库先吃透就够你跑通基础框架。 外汇和贵金属波动剧烈、杠杆风险高,用这些工程做回测和验证时,任何信号都只是概率倾向,别当确定性依据。 有空就打开 MT5 把 ZIP 里的 EA 加载到策略测试器,先确认编译能过、日志不报错,再谈改参数。