价格行为分析工具包开发(第 17 部分):TrendLoom EA 工具·综合运用
「面板按钮怎么触发多周期趋势判断」
这段代码是趋势面板里按钮事件处理的尾巴,以及结果刷新和 SMA 取值的辅助函数。按钮点击后按 sparam 区分:短周期刷单/中级趋势走 H1+M15 组合,长期趋势则强制拉取 H1、D1、W1 三个周期做 AnalyzeTimeframes,结果拼成字符串后同时写标签和弹 Alert。 UpdateResults 只干两件事:把文字塞进 m_lblResults 对象,然后调 ChartRedraw 强制重绘,避免 MT5 图表懒刷新导致你看到旧结论。外汇和贵金属波动大,这类按钮触发的结果只是概率性倾向,别当确定性信号。 GetSMA 用 iMA 建句柄,MODE_SMA + PRICE_CLOSE 取收盘价简单移动平均。CopyBuffer 只拷 1 根(shift 位置),失败就 Print 报错并返回 0.0——实盘里若频繁打印 Failed to copy buffer,多半是周期切换时句柄未释放,建议打开 MT5 专家日志核对。
class="type">class="kw">string out = "Short Scalper/Mid Trend: " + res; UpdateResults(out); Alert(out); class="kw">return true; } else if(sparam == "btnLongTerm") { class="type">class="kw">string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_D1, PERIOD_W1); class="type">class="kw">string out = "Long Term Trend: " + res; UpdateResults(out); Alert(out); class="kw">return true; } class="kw">return false; } class="type">bool ChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam) { class="kw">return OnEvent(id, lparam, dparam, sparam); } class=class="str">"cmt">// Update the results label and refresh the chart class="type">void UpdateResults(const class="type">class="kw">string &result) { m_lblResults.Text("Analysis Result: " + result); ChartRedraw(); } }; class=class="str">"cmt">// Global instance of the TrendLoom Panel CTrendLoomPanel TrendPanel; class=class="str">"cmt">//------------------------------------------------------------------------------ class=class="str">"cmt">// Helper functions(core analysis logic) class=class="str">"cmt">//------------------------------------------------------------------------------ class="type">class="kw">double GetSMA(class="type">class="kw">string symbol, ENUM_TIMEFRAMES timeframe, class="type">int period, class="type">int shift) { class="type">int handle = iMA(symbol, timeframe, period, class="num">0, MODE_SMA, PRICE_CLOSE); if(handle == INVALID_HANDLE) { Print("Failed to create iMA handle for timeframe ", timeframe); class="kw">return class="num">0.0; } class="type">class="kw">double sma[]; class=class="str">"cmt">// dynamic array to store SMA values if(CopyBuffer(handle, class="num">0, shift, class="num">1, sma) <= class="num">0) { Print("Failed to copy buffer for timeframe ", timeframe);
三周期收盘与均线的共振判定
多周期趋势过滤的核心,是把三个周期各自的价格与均线关系量化成 -1 / 0 / 1 的信号,再求和看是否达到共振阈值。下面这段逻辑用 50 周期 SMA 配合上一根已收盘 K 线(shift=1)的收盘价做比对,读者可直接在 MT5 里改 period 或 shift 验证灵敏度。 signal 的算法很直白:收盘价高于 SMA 记 +1,低于记 -1,相等记 0。当三个信号之和 sum >= 2 时返回 BUY,<= -2 返回 SELL,其余为 NEUTRAL——也就是说至少两个周期同向才给出方向倾向,单周期反向不会触发交易指令。 初始化里把面板创建出来,若 TrendPanel.CreateTrendPanel 失败直接 INIT_FAILED,坐标由 PanelX/PanelY 控制,高度锁在 400 像素。外汇与贵金属波动剧烈,这种多周期共振只降低噪音、不消除方向误判概率,实盘前务必用历史数据回测不同周期组合。
class="type">class="kw">string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3) { class="type">int period = class="num">50; class="type">int shift = class="num">1; class=class="str">"cmt">// last completed candle class="type">class="kw">double price1 = iClose(_Symbol, tf1, shift); class="type">class="kw">double sma1 = GetSMA(_Symbol, tf1, period, shift); class="type">int signal1 = (price1 > sma1) ? class="num">1 : (price1 < sma1 ? -class="num">1 : class="num">0); class="type">class="kw">double price2 = iClose(_Symbol, tf2, shift); class="type">class="kw">double sma2 = GetSMA(_Symbol, tf2, period, shift); class="type">int signal2 = (price2 > sma2) ? class="num">1 : (price2 < sma2 ? -class="num">1 : class="num">0); class="type">class="kw">double price3 = iClose(_Symbol, tf3, shift); class="type">class="kw">double sma3 = GetSMA(_Symbol, tf3, period, shift); class="type">int signal3 = (price3 > sma3) ? class="num">1 : (price3 < sma3 ? -class="num">1 : class="num">0); class="type">int sum = signal1 + signal2 + signal3; if(sum >= class="num">2) class="kw">return "BUY"; else if(sum <= -class="num">2) class="kw">return "SELL"; else class="kw">return "NEUTRAL"; } class="type">int OnInit() { if(!TrendPanel.CreateTrendPanel(class="num">0, "TrendLoom Panel", PanelX, PanelY, PanelX + PanelWidth + class="num">20, PanelY + class="num">400)) { Print("Failed to create TrendLoom Panel."); class="kw">return INIT_FAILED; } class="kw">return INIT_SUCCEEDED; } class="type">void OnDeinit(const class="type">int reason) { TrendPanel.Destroy(reason); }
◍ 把图表交互交给面板对象
在 MT5 的 EA 或指标里,图表事件(鼠标点击、键盘、自定义事件等)若想驱动自定义面板,不需要在 OnChartEvent 里写一堆分支判断。只要面板类实例已存在,直接把事件参数透传给它的 ChartEvent 方法即可。 上面这段源码展示了最简写法:OnChartEvent 仅做一件事,调用 TrendPanel.ChartEvent(id, lparam, dparam, sparam)。这意味着所有按钮响应、拖拽逻辑都被封装在 TrendPanel 类内部,主程序保持干净。 实盘验证时你可以这样测:在面板类里给 ChartEvent 加一行 Print(id) ,编译挂到 EURUSD 的 M1 图,点几下面板按钮,终端里应能看到 id 数值随交互变化(如 17 对应鼠标点击图表对象)。外汇与贵金属杠杆高,面板只是辅助观察,信号失效时止损纪律不能丢。
class=class="str">"cmt">//| Chart Event Handler | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam) { TrendPanel.ChartEvent(id, lparam, dparam, sparam); } class=class="str">"cmt">//+------------------------------------------------------------------+
「用 V75 1s 跑出来的实测反馈」
任何 EA 在接实盘前都得先过两关:历史数据回测看无风险下的理论表现,再用模拟账户看实时反应。这两步能逼出参数盲点,把工具磨到能信手用。 我自己在 Volatility 75 (1s) 上做了实测,EA 每个按钮都按预期触发,点下去分析结果几乎即时刷新。该品种波动极快,能跑顺说明事件响应链路没拖泥带水。 图 4 是 V75 1s 的测试截屏,图 5 切到 M1 周期延续同一笔信号后的市场行为,视野拉宽后更能看清信号触发位置与后续价格推移的关系。外汇与合成指数类产品杠杆高、跳空频繁,这类测试结果仅代表特定时段样本,换周期或换品种表现可能明显偏离。
一点提醒
这套 TrendLoom 工具从 2024 年 10 月到 2025 年 2 月累计发布了 17 个组件,从图表投影仪到四分位绘制脚本,覆盖价格行为、波动率与多周期面板。作者实测中确认它对市场分析有正向辅助,但明确它只是辅助而非最终信号源。 外汇与贵金属本身高风险,任何 EA 或指标都只是概率工具。建议你把 TrendLoom_EA.mq5 拖进 MT5 策略测试器,按自己的品种和周期调布林带、RSI、ATR 参数,再用它去确认你原有策略的入场倾向,而不是单独跟单。 工具迭代很快,例如分析预测器在 02/12/24 已到 1.1 版并接了 Telegram 推送,后面还有 FibVWAP 走 Python 分析。真要上手,先开模拟盘跑两周,看信号延迟和重绘情况再决定实盘仓位。