开发回放系统(第 38 部分):铺路(II)·进阶篇
📘

开发回放系统(第 38 部分):铺路(II)·进阶篇

第 2/2 篇

用 iCustom 把自定义指标拉进 EA

在 MT5 里写 EA 时,若信号来自第三方或自己写的自定义指标,标准内置函数 iMA、iRSI 都派不上用场,只能走 iCustom 这一条接口。 它的前三个参数是硬门槛:symbol 填交易品种名(如 "XAUUSD"),period 用 ENUM_TIMEFRAMES 枚举指定周期,name 则是 Indicators 文件夹下的指标文件名(含子目录路径)。后面跟着的省略号代表指标自身的输入参数,顺序和类型必须跟原指标设置窗口里一一对应,错一位就可能取到空缓冲区。 外汇与贵金属杠杆高、滑点大,用 iCustom 取信号做回测时,先在策略测试器里打印缓冲区数值确认绑定成功,再谈逻辑,否则容易把乱码当买卖点。

MQL5 / C++
class="type">int   iCustom(
                      class="type">class="kw">string           symbol,   class=class="str">"cmt">// symbol name
                      ENUM_TIMEFRAMES  period,   class=class="str">"cmt">// period
                      class="type">class="kw">string           name      class=class="str">"cmt">// folder/custom indicator name
                      ...                       class=class="str">"cmt">// list of indicator parameters
                      );

「IndicatorCreate 与 iCustom 的底层调用差异」

调用自定义指标在 MT5 里通常走两条路:iCustom 是派生函数,把参数打包隐藏掉,写起来省事;IndicatorCreate 属于基本函数,逼你把指标加载过程一步步建模出来。前者适合快速挂一个现成指标,后者在需要动态控制参数数组、或在运行时判断图表上是否已存在该指标时更灵活。 看下面这段 EA 初始化代码:若图表上找不到名为 SWAP MSG 的指标,才用 IndicatorCreate 现场创建。注意第 17 行 ArrayResize(params, 2) —— 因为指标名占 1 个 STRING 位,外加 1 个 double 参数 user00,所以数组长度是参数个数加 1。如果你传 5 个参数,就得分配 6 个元素。 MQL5 数组从零计数,第 18–19 行先填 params[0]:type 必须是 TYPE_STRING,string_value 写指标名且不加 .ex5 扩展名(系统默认找可执行文件)。从第 20 行起才是真实参数,类型声明错一位就会在运行时报错。 类型与取值变量的对应关系不能乱:TYPE_DOUBLE / TYPE_FLOAT 走 double_value,TYPE_STRING 走 string_value,其余布尔、整型、颜色、时间等十余种统统进 integer_value。这个映射表里列了 13 种标识符,照表填就不会踩坑。外汇与贵金属杠杆高,实盘前务必在策略测试器用历史数据验证指标句柄返回非 INVALID_HANDLE。

MQL5 / C++
class="macro">#class="kw">property copyright "Daniel Jose"
class="macro">#class="kw">property link      ""
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//+------------------------------------------------------------------+
input class="type">class="kw">double user00 = class="num">2.2;
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int m_handle;
class="type">long m_id;
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
{
    class="type">MqlParam params[];
    
    m_id = ChartID();      
    if ((m_handle = ChartIndicatorGet(m_id, class="num">0, "SWAP MSG")) == INVALID_HANDLE)
    {
        ArrayResize(params, class="num">2);
        params[class="num">0].type = TYPE_STRING;
        params[class="num">0].string_value = "Mode Swap\\SWAP MSG";
        params[class="num">1].type = TYPE_DOUBLE;
        params[class="num">1].double_value = user00;
        m_handle = IndicatorCreate(NULL, PERIOD_CURRENT, IND_CUSTOM, ArraySize(params), params);
        ChartIndicatorAdd(m_id, class="num">0, m_handle);
    }
    Print("Indicator loading result:", m_handle != INVALID_HANDLE ? "Success" : "Failed");
    

◍ 把隔夜利息提示从图表上干净卸掉

EA 退出时最容易漏掉的一件事,就是留在图表上的自定义指标对象没清干净,下次加载会报重复名称。上面这段 OnDeinit 里用 ChartIndicatorDelete 按子窗口 0 和名称 "SWAP MSG" 精准删除,不依赖全局遍历。 紧接着的 IndicatorRelease 释放 m_handle 句柄,避免指标缓冲区驻留内存;MT5 里句柄不释放,重复加载同一标的可能让句柄计数悄悄累加。 OnTick 留空不是疏忽,这个 EA 只在初始化阶段把掉期信息写一次到图表,行情跳动不需要任何重算,所以空函数反而最省资源。

MQL5 / C++
class="num">27.    class="kw">return INIT_SUCCEEDED;
class="num">28. }
class="num">29. class=class="str">"cmt">//+------------------------------------------------------------------+
class="num">30. class="type">void OnDeinit(const class="type">int reason)
class="num">31. {
class="num">32.    ChartIndicatorDelete(m_id, class="num">0, "SWAP MSG");
class="num">33.    IndicatorRelease(m_handle);
class="num">34. }
class="num">35. class=class="str">"cmt">//+------------------------------------------------------------------+
class="num">36. class="type">void OnTick()
class="num">37. {
class="num">38. }
class="num">39. class=class="str">"cmt">//+------------------------------------------------------------------+

IndicatorCreate 的体力活与 IndicatorParameters 的妙用

把参数逐个映射到自定义指标时,第 20 行写标识符、第 21 行接变量值,这套动作对每个要传的参数都得重复一次。本例只用一个参数,所以只动那一个;若参数多了,这种手写映射会明显拖慢开发节奏。 在 MT5 里直接调 IndicatorCreate 比用封装好的 iCustom 更费劳力——所有字段得自己填齐。我们把参数配置集中放在调用前的段落(如第 22 行实际创建指标),好处是改指标名或参数数量时不用回头改创建那一行,降低出错概率。 另一个值得记下的函数是 IndicatorParameters:它能让 MT5 回填某个已加载指标的真实配置。当图表上多个指标因行情突变要花几分钟才稳定初始化时,EA 可先调它拿到准确设置,再用 IndicatorCreate 改配置,触发器立刻生效,买卖逻辑不用等。 在系列文章《创建一个自动工作的 EA(第 15 部分):自动化(VII)》里,曾演示过以指标作为EA买卖触发器的做法;IndicatorParameters 能让同一套 EA 少等初始化、更快响应。外汇与贵金属杠杆高、滑点突发,自动读取指标配置也仅是降低延迟,不消除方向误判风险。本回放不展开该函数代码,只点出它实用。

「把这条线请下神坛」

向指标推送数据这条路已经走通,示例代码里 EA 用 CustomIndicator 的 Buffer 写入,脚本也能干同样的活,但服务(service)在撰写本文时因运行机制限制无法直接承担这件事。 接下来真正的缺口在反向传输:指标怎么把数据交回智能系统,而且得绕开全局终端变量、不编译一堆程序以免漏编。回放系统里接 Chat Trader 还差这一步。 下一篇会专门拆指标到 EA 的通道,距离可用的图表交易者还差最后一段组装。外汇与贵金属市场高波动,这类架构实验先在策略测试器里跑,别直接上实盘。

常见问题

用 iCustom 按指标文件名、参数顺序取句柄,再用 CopyBuffer 拿缓冲区数据;注意参数顺序和索引必须和指标里定义的一致。
iCustom 是便捷封装,适合快速挂别人写的指标;IndicatorCreate 走底层句柄管理,能精细控制参数和生命周期,但代码量明显更大。
可以,小布能按你设定的指标条件做 AIGC 诊断,把异动直接推到品种页,不用自己写监听代码。
在指标初始化里别画文本对象,或在 deinit 里用 ObjectDelete 按名清理;EA 加载时也要避开重复创建的注释函数。
单一线在震荡和跳空里会频繁假突破,概率上只是参考;外汇贵金属波动大,高风险下别把它当唯一依据。