美林(Merrill)形态(基础篇)
「美林形态的 MT5 验证起点」
美林(Merrill)形态是一类基于价格折线几何关系识别反转区域的技术结构,在 MT5 环境里可直接用历史数据做可视化回看。 一位叫 Alexander Fedosov 的作者于 2019 年 10 月 3 日 07:53 在 MT5 社区贴出该主题,截至统计时获得 8 755 次浏览与 18 条讨论,说明这类形态在实盘群体里有稳定关注度。 要做第一步验证,不需要立刻写策略:打开 MT5 的「策略测试器」→ 载入任意欧美或 XAUUSD 的 H1 历史,手动标出相邻三个折点构成的非对称 N 字,观察第三折后 20~40 根 K 线是否出现反向刺透。外汇与贵金属杠杆高,形态失效时回撤可能快速吃掉前期盈利,仅作概率参考。 想进一步量化,可基于 MT5 内置指标接口开发小型测试脚本,把「形态识别 + 出场规则」固化为可复跑任务,后续小节会拆具体代码。
从利维到美林:图表形态分类的来路
- 年罗伯特·利维用五点价格波动形态做系统性验证,结果没跑出显著绩效。十年后亚瑟·美林接手,把形态按 M 和 W 两类归并,每类 16 种再加子类别,工作才落到可操作的框架上。
美林圈出 6 个重点子类别:上行趋势、下行趋势、三角形、扩展、头肩、逆头肩。这套分法至今是形态识别的底层参照,而不是随便画两条线就算数。 在 MT5 里值得做的是:把美林定义好的形态拿去和实时行情做相关性回测,并且换数据维度试——收盘价、最高最低价、甚至振荡器数值,同一形态在不同输入下的触发率可能差出一倍。外汇与贵金属波动受杠杆和突发事件影响,形态失效概率偏高,验证时务必带止损逻辑。
◍ 美林 M/W 形态落在哪类数据上
美林形态按轮廓分成两类:像字母 M 和 W 的图案,各自包含 16 种变体,差异全在构成形态的五个点的相互排列上。出现特定形态时,价格朝某个方向移动的倾向可以被预期,但这是概率性事件,不是确定性结论。 我们实际要扫描的数据源分两块。第一块是基于 OHLC 的线性价格图:先用收盘价线图(如 USDCAD H1)肉眼就能看到若干 M/W 雏形,再依次用开盘、最高、最低价线图排查。第二块是振荡器序列,包括 ATR(波动率)、CCI(价均偏离)、DeMarker、FRC(推动力)、WPR(超买超卖)、RSI、Momentum(固定周期价格变化)。 评估方法沿用烛台研究里的套路:在样本内标定形态出现位置,随后跟踪其后价格走势,收集命中数据算效能。外汇与贵金属杠杆高、滑点突变频繁,同一形态在不同品种上的胜率可能落差极大,务必自己跑样本再信。
「美林形态测试器的面板与内核怎么搭」
做这套形态扫描工具前,先把界面和参数域切清楚:分析选卡管形态类型、周期、趋势阈值和品种过滤;设置选卡管指标、权重系数和语言;EA 属性窗(F7)管具体指标参数。分析选卡里「趋势阈值(点数)」是关键输入——形态走完之后,价格须在最多 3 根蜡烛内触及该盈利点数,才计入有效样本。 结果表七列直接决定你能读出什么:图形名称(如 M10 / W12)、发现数、时间帧、上行 P、下行 P,以及 K 上行 / K 下行比率——后者衡量价格达到阈值的快慢。默认品种过滤设为 Major,只拉主要货币对;取消勾选才显示全部可交易品种,外汇和贵金属波动属性不同,批量扫全部前先想清楚历史深度够不够。 核心循环在 GetResult():用 RATING_SET 结构(6 个 int)承接 a_uptrend / b_uptrend 等评级,例如 5 位小数下阈值 100 点、单蜡烛触及则 a_uptrend=1,两蜡烛触及进 b_uptrend。ChangeSymbol1() 在选品种或改阈值时触发,把数据喂给 GetPatternType() 搜形态、GetCategory() 评效率、AddRow() 落表。 实跑前先下齐对应品种历史数据;别一次性勾全部形态加全部周期,处理耗时会拖垮 MT5。不设时间帧或形态、日期区间非法,是最常卡住的两类报错。权重系数怎么改 K 比率,得回头看形态效率计算那篇,乱填系数表格就是废的。 下面这段是 GUI 搭建入口,CreateGUI() 先建主面板再开日期对话框,分析选卡里图案按钮从 (10,10) 起排、周期标签在 y=105、周期按钮 y=125、品种过滤框 y=180——坐标写死,改布局直接动这几个数。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Create the program GUI | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CProgram::CreateGUI(class="type">void) { class=class="str">"cmt">//--- Create the panel if(!CreateWindow("Merrill Patterns")) class="kw">return(false); class=class="str">"cmt">//--- Create the dialog window if(!CreateWindowSetting1("Setting dates")) class="kw">return(false); class=class="str">"cmt">//--- Complete GUI creation CWndEvents::CompletedGUI(); class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Analyze tab | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Create the pattern set buttons if(!CreatePatternSet(m_patterns,class="num">10,class="num">10)) class="kw">return(false); class=class="str">"cmt">//--- Timeframe header if(!CreateTFLabel(m_text_labels[class="num">1],class="num">10,class="num">105,class="num">0)) class="kw">return(false); class=class="str">"cmt">//--- Create the timeframe set buttons if(!CreateTimeframeSet(m_timeframes,class="num">10,class="num">125,class="num">0)) class="kw">return(false); class=class="str">"cmt">//--- Field for searching the symbol filter if(!CreateSymbolsFilter(m_symb_filter1,m_request1,class="num">10,class="num">180,class="num">0))
面板控件的初始化坐标与返回值链
这段初始化逻辑把分析页与设置页的所有图形控件一口气建出来,任何一步失败就直接 return(false),整套 UI 起不来。坐标参数都是写死的像素值,比如日期范围按钮放在 (280,180)、盈利阈值输入框在 (400,180) 且默认宽度 100,符号表从左上角 (10,225) 开始排。 设置页里三组系数框 K1/K2/K3 的默认分别是 1、0.5、0.25,横向间隔 100 像素,都挂在 (10,140) 基准线下。语言设置控件在 (10,180),状态栏高 26,这些数字直接决定你在 MT5 里看到面板时的布局疏密。 日期选择弹窗单独用 m_window[2],尺寸锁死 372×230,锚定在日期按钮正下方(y 坐标 = 按钮 y + 按钮高)。想改面板拥挤感,优先动这些常量而不是重排函数调用。 外汇与贵金属品种波动剧烈,这类自定义面板仅用于历史统计与参数可视化,不构成任何方向建议,实盘前请在策略测试器里跑通再挂真账户。
class="kw">return(false); class=class="str">"cmt">//--- Create the button for selecting a date range if(!CreateDateRange(m_request3,class="num">280,class="num">180,class="num">0)) class="kw">return(false); class=class="str">"cmt">//--- Create the field for entering the profit threshold value if(!CreateThresholdValue(m_threshold1,class="num">400,class="num">180,class="num">100,class="num">0)) class="kw">return(false); class=class="str">"cmt">//--- Create the symbol table if(!CreateSymbTable(m_symb_table1,class="num">10,class="num">225,class="num">0)) class="kw">return(false); class=class="str">"cmt">//--- Create the result table if(!CreateTable1(m_table1,class="num">120,class="num">225,class="num">0)) class="kw">return(false); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Settings tab | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- if(!CreateButtonsGroup1(class="num">10,class="num">50)) class="kw">return(false); class=class="str">"cmt">//--- Text labels if(!CreateTextLabel(m_text_labels[class="num">0],class="num">10,class="num">100)) class="kw">return(false); if(!CreateTextLabel(m_text_labels[class="num">3],class="num">10,class="num">10)) class="kw">return(false); class=class="str">"cmt">//--- Input fields if(!CreateCoef(m_coef1,class="num">10,class="num">140,"K1",class="num">1)) class="kw">return(false); if(!CreateCoef(m_coef2,class="num">100,class="num">140,"K2",class="num">0.5)) class="kw">return(false); if(!CreateCoef(m_coef3,class="num">200,class="num">140,"K3",class="num">0.25)) class="kw">return(false); if(!CreateLanguageSetting(m_lang_setting,class="num">10,class="num">180,class="num">1)) class="kw">return(false); class=class="str">"cmt">//--- Status bar if(!CreateStatusBar(class="num">1,class="num">26)) class="kw">return(false); class=class="str">"cmt">//--- class="kw">return(true); } class=class="str">"cmt">//+---------------------------------------------------------------------------------+ class=class="str">"cmt">//| Create the dialog window for selecting the range of dates in the Analysis tab | class=class="str">"cmt">//+---------------------------------------------------------------------------------+ class="type">bool CProgram::CreateWindowSetting1(class="kw">const class="type">class="kw">string caption_text) { class=class="str">"cmt">//--- Add the window pointer to the window array CWndContainer::AddWindow(m_window[class="num">2]); class=class="str">"cmt">//--- Coordinates class="type">int x=m_request3.X(); class="type">int y=m_request3.Y()+m_request3.YSize(); class=class="str">"cmt">//--- Properties m_window[class="num">2].XSize(class="num">372); m_window[class="num">2].YSize(class="num">230); m_window[class="num">2].WindowType(W_DIALOG); class=class="str">"cmt">//--- Create the form if(!m_window[class="num">2].CreateWindow(m_chart_id,m_subwin,caption_text,x,y))
◍ 把控件和指标参数接进主程序
这段收尾代码负责把日历、时间编辑框等 GUI 控件创建好,再在外层用 input 把多空决策需要的指标周期暴露给 EA 面板。控件若有一个创建失败就直接 return(false),保证面板不完整时不开机运行。 日历控件用 CreateCalendar 挂到第三个子窗口(索引2):m_calendar1 从 2019.01.01 起、左距10像素;m_calendar2 用 Today() 动态取当天、左距201像素,两者高度都是25。时间框 CreateTimeEdit 同样挂在索引2,y 坐标200,左距分别是10和200。 指标侧默认周期偏小:ATR/CCI/DeM/WPR/RSI 全是5,ForceIndex 取13并用 SMA 对收盘价和 tick 量加权。外汇与贵金属波动剧烈,小周期组合在消息行情里可能频繁伪信号,上 MT5 把 Inp_ATR_Peroid 调到14对比一下过滤效果。
class="kw">return(false); class=class="str">"cmt">//--- if(!CreateCalendar(m_calendar1,m_window[class="num">2],class="num">10,class="num">25,D&class="macro">#x27;class="num">01.01.class="num">2019&class="macro">#x27;,class="num">1)) class="kw">return(false); if(!CreateCalendar(m_calendar2,m_window[class="num">2],class="num">201,class="num">25,m_calendar2.Today(),class="num">1)) class="kw">return(false); class=class="str">"cmt">//--- if(!CreateTimeEdit(m_time_edit1,m_window[class="num">2],class="num">10,class="num">200,"Time",class="num">1)) class="kw">return(false); if(!CreateTimeEdit(m_time_edit2,m_window[class="num">2],class="num">200,class="num">200,"Time",class="num">1)) class="kw">return(false); class=class="str">"cmt">//--- class="kw">return(true); } class=class="str">"cmt">//--- Include the application class class="macro">#include "Program.mqh" CProgram program; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA inputs | class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">input ENUM_APPLIED_PRICE Inp_Price1 = PRICE_CLOSE; class=class="str">"cmt">// Applied price class="kw">input class="type">int Inp_ATR_Peroid = class="num">5; class=class="str">"cmt">// ATR Period class="kw">input class="type">int Inp_CCI_Peroid = class="num">5; class=class="str">"cmt">// CCI Period class="kw">input class="type">int Inp_DeM_Peroid = class="num">5; class=class="str">"cmt">// DeMarker Period class="kw">input class="type">int Inp_ForcePeriod = class="num">13; class=class="str">"cmt">// ForceIndex Period class="kw">input ENUM_MA_METHOD Inp_ForceMAMethod = MODE_SMA; class=class="str">"cmt">// ForceIndex MA method class="kw">input ENUM_APPLIED_PRICE Inp_ForceAppliedPrice = PRICE_CLOSE; class=class="str">"cmt">// ForceIndex Applied price class="kw">input ENUM_APPLIED_VOLUME Inp_ForceAppliedVolume= VOLUME_TICK; class=class="str">"cmt">// ForceIndex Volumes class="kw">input class="type">int Inp_WPR_Period = class="num">5; class=class="str">"cmt">// WPR Period class="kw">input class="type">int Inp_RSI_Period = class="num">5; class=class="str">"cmt">// RSI Period class=class="str">"cmt">//+------------------------------------------------------------------+