如何利用 MQL5 创建简单的多币种智能交易系统(第 3 部分):添加交易品种、前缀和/或后缀、以及交易时段·进阶篇
⚙️

如何利用 MQL5 创建简单的多币种智能交易系统(第 3 部分):添加交易品种、前缀和/或后缀、以及交易时段·进阶篇

(2/3)· 当经纪商给品种加前缀后缀、还想按交易时段开关仓位,标准多币种EA为何直接失效

含代码示例偏理论 第 2/3 篇

不少交易者把上篇的多币种EA直接挂到带前缀后缀的经纪商账户上,结果30个品种一个都没认出来。更隐蔽的是,以为靠手动改输入栏就能绕开,却漏掉了交易时段冲突导致的无效下单。这些坑在写函数前就得想清楚。

「EA 风控与信号参数的输入声明」

在 MT5 写 EA 时,先把止损、止盈和移动止损的开关与数值用 input 暴露出来,是回测和实盘调参的基础。下面这段声明把自动止损、固定点数止损、自动止盈、移动止损触发距离等全部外置,实盘里改一个数字就能换一套风控逻辑。 自动止损开启时 SLval 不起作用,关闭后才会用输入的 30 点作为固定止损;同理自动止盈关掉才读 TPval 的 10 点。移动止损部分,TSmin=5 表示浮盈满 5 点才开始跟,TPmin=25 是移动止盈的目标缓冲,TSval=5 为回撤跟踪距离。 信号类开关里,Close_by_Opps=Yes 让反向信号直接平掉原单,SaveOnRev=Yes 则在弱信号出现时落袋保全。其余如 alerts、UseEmailAlert、UseSendnotify 控制提示渠道,magicEA=2023102 用于区分本 EA 订单,避免和别的脚本混单。外汇与贵金属波动剧烈,这类参数组合仅降低人为犹豫,不消除爆仓风险,参数改完务必在策略测试器跑至少 3 个月 tick 数据。

MQL5 / C++
input YN                autosl = Yes;                 class=class="str">"cmt">// Use Automatic Calculation Stop Loss(Yes) or(No)
input class="type">class="kw">double             SLval = class="num">30;                   class=class="str">"cmt">// If Not Use Automatic SL - Input SL value in Pips
input YN                 use_tp = Yes;                 class=class="str">"cmt">// Use Order Take Profit(Yes) or(No)
input YN                 autotp = Yes;                 class=class="str">"cmt">// Use Automatic Calculation Take Profit(Yes) or(No)
input class="type">class="kw">double             TPval = class="num">10;                   class=class="str">"cmt">// If Not Use Automatic TP - Input TP value in Pips
input YN             TrailingSLTP = Yes;               class=class="str">"cmt">// Use Trailing SL/TP(Yes) or(No)
input YN                 autotrl = Yes;                class=class="str">"cmt">// Use Automatic Trailing(Yes) or(No)
input class="type">class="kw">double             TSval = class="num">5;                    class=class="str">"cmt">// If Not Use Automatic Trailing Input Trailing value in Pips
input class="type">class="kw">double             TSmin = class="num">5;                    class=class="str">"cmt">// Minimum Pips to start Trailing Stop
input class="type">class="kw">double             TPmin = class="num">25;                   class=class="str">"cmt">// Input Trailing Profit Value in Pips
input YN             Close_by_Opps = Yes;              class=class="str">"cmt">// Close Trade By Opposite Signal(Yes) or(No)
input YN                 SaveOnRev = Yes;              class=class="str">"cmt">// Close Trade and Save profit due to weak signal(Yes) or(No)
class=class="str">"cmt">//--Others Expert Advisor Parameter
input group              "=== Others Expert Advisor Parameter ===" ; class=class="str">"cmt">// Others EA Parameter
input YN                 alerts = Yes;                 class=class="str">"cmt">// Display Alerts / Messages(Yes) or(No)
input YN             UseEmailAlert = No;               class=class="str">"cmt">// Email Alert(Yes) or(No)
input YN             UseSendnotify = No;               class=class="str">"cmt">// Send Notification(Yes) or(No)
input YN       trade_info_display = Yes;               class=class="str">"cmt">// Select Display Trading Info on Chart(Yes) or(No)
input class="type">class="kw">ulong               magicEA = class="num">2023102;            class=class="str">"cmt">// Expert ID(Magic Number)
class=class="str">"cmt">//---
class=class="str">"cmt">//+------------------------------------------------------------------+

EA 类里的时空与品种前缀字段

把交易逻辑塞进一个 MQL5 类里,第一件事是把时间切片和品种命名规则先固化成私有成员。下面这段 class MCEA 的 private 区,就是给后续信号计算铺底:年、月、日、时、分、秒六个 int 存当前 Bar 的时间分量,方便后面做时段过滤。 品种前缀后缀的解析也提前留了坑:pre、suf 两个 string 配合 inpre、insuf、posCur1、posCur2 记录前缀后缀在品种名里的位置,Brooker 里带 'm.' 或 '.s' 这类后缀的标的就能被自动识别。 交易时段变量更直白:ishour/onhour 是开关钟点,rem/znop/zncl/zntm 及 Ses01Op~Ses05Cl 等 datetime 把五个会话段的open/close 时间全记下来。外汇和贵金属杠杆高、跳空频繁,这类时段边界最好用真实历史 session 数据校准,别拍脑袋写死。 代码逐行看,注释已经标了用途,复制进 MT5 的 include 头文件就能编译,改 Ses 系列变量可立刻切换你盯的盘口。

MQL5 / C++
class=class="str">"cmt">//| Class for working Expert Advisor                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class MCEA
  {
class=class="str">"cmt">//---
   class="kw">private:
   class=class="str">"cmt">//---- 
   class="type">int               x_year;       class=class="str">"cmt">// Year 
   class="type">int               x_mon;        class=class="str">"cmt">// Month 
   class="type">int               x_day;        class=class="str">"cmt">// Day of the month 
   class="type">int               x_hour;       class=class="str">"cmt">// Hour in a day 
   class="type">int               x_min;        class=class="str">"cmt">// Minutes 
   class="type">int               x_sec;        class=class="str">"cmt">// Seconds
   class=class="str">"cmt">//--
   class="type">int               oBm,
                     oSm,
                     ldig;
   class=class="str">"cmt">//--- Variables used in prefix and suffix symbols
   class="type">int               posCur1,
                     posCur2;
   class="type">int               inpre,
                     insuf;
   class="type">class="kw">string            pre,suf;      
   class=class="str">"cmt">//--- Variables are used in Trading Time Zone
   class="type">int               ishour,
                     onhour;
   class="type">class="kw">datetime          rem,
                     znop,
                     zncl,
                     zntm;
   class="type">class="kw">datetime          SesCuOp,
                     SesCuCl,
                     Ses01Op,
                     Ses01Cl,
                     Ses02Op,
                     Ses02Cl,
                     Ses03Op,
                     Ses03Cl,
                     Ses04Op,
                     Ses04Cl,
                     Ses05Op,
                     Ses05Cl,
                     SesNoOp,

◍ EA 全局变量的声明骨架

这段声明块定义了多周期交易面板最底层的数据容器,开 MT5 把代码贴进头文件就能看到编译器的变量布局。 先是一组字符串:SesNoCl 存会话编号,tz_ses / tz_opn / tz_cls 管时区显示,tmop01~tmop05 与 tmcl01~tmcl05 对应五个交易时段的开收盘标签,tmopcu / tmclcu 是当前时段,tmopno / tmclno 是无时段兜底值。 数值侧 LotPS 记录每标准手规模,slv / tpv 是止损止盈价,pip / xpip 区分点值与普通 pip,differ 留作价差或偏离计算,floatprofit 与 fixclprofit 分别承接浮动与固定平仓收益。 行情数组 OPEN[] HIGH[] LOW[] CLOSE[] 配合 TIME[] 与 closetime,构成 K 线序列的裸容器;末尾三个 void 函数 SetSymbolNamePS、HandlingSymbolArrays、Set_Time_Zone 负责符号名、数组填充和时区写入,调用前这些数组都是空的。 外汇与贵金属杠杆高,这类全局容器若未初始化就直接读数组,回测会静默出错,实盘可能触发异常平仓。

MQL5 / C++
            SesNoCl;
class=class="str">"cmt">//--
class="type">class="kw">string              tz_ses,
                    tz_opn,
                    tz_cls;
class=class="str">"cmt">//--
class="type">class="kw">string              tmopcu,
                    tmclcu,
                    tmop01,
                    tmcl01,
                    tmop02,
                    tmcl02,
                    tmop03,
                    tmcl03,
                    tmop04,
                    tmcl04,
                    tmop05,
                    tmcl05,
                    tmopno,
                    tmclno;            
class=class="str">"cmt">//----------------------    
class=class="str">"cmt">//--
class="type">class="kw">double              LotPS;
class="type">class="kw">double              slv,
                    tpv,
                    pip,
                    xpip;
class="type">class="kw">double              differ;            
class="type">class="kw">double              floatprofit,
                    fixclprofit;
class=class="str">"cmt">//--
class="type">class="kw">string              pairs,
                    hariini,
                    daytrade,
                    trade_mode;
class=class="str">"cmt">//--
class="type">class="kw">double              OPEN[],
                    HIGH[],
                    LOW[],
                    CLOSE[];
class="type">class="kw">datetime            TIME[];
class="type">class="kw">datetime            closetime;
class=class="str">"cmt">//--
class=class="str">"cmt">//------------

class=class="str">"cmt">//------------
class="type">void                SetSymbolNamePS(class="type">void);
class="type">void                HandlingSymbolArrays(class="type">void);
class="type">void                Set_Time_Zone(class="type">void);

「EA 内部函数接口的分组逻辑」

这段声明清单把一个 MTF 顺势 EA 的底层工具函数按用途切成了四组,方便在 MT5 里直接对照排查调用链。 时间相关一组:Time_Zone 无参设置时区,Trade_session 返回当前是否处于可交易时段(bool),PosTimeZone 取持仓时区字符串,ThisTime 与 ReqTime 分别按 reqmode 取本地/服务器时间整数,误差通常控制在 1 秒级。 信号与手数一组:DirectionMove 判货币对方向倾向,GetPSARSignalMTF 取多周期 SAR 信号,PARSAR05 与 PARSARMTF 分别处理单周期与指定周期(ENUM_TIMEFRAMES)的 SAR 判定,LotDig 取品种小数位。 风控计算一组:MLots 算建议手数,NonZeroDiv 防零除,OrderSLSet/OrderTPSet 按挂单类型算止损止盈价,SetOrderSL/SetOrderTP 按持仓类型算,TSPrice 按追踪止损类型回推价格。 字符串与配置一组:ReqDate、TF2Str、timehr 做时间周期格式化,TradingDay 取交易日,AccountMode 返回账户模式,GetCommentForOrder 直接回传 expname 作订单备注。 在 MT5 导航器里把这类头文件展开,逐组核对函数名与返回类型,能快速定位信号计算或风控模块改动的落点。外汇与贵金属杠杆品种波动剧烈,任何函数改动都建议先开模拟账户验证。

MQL5 / C++
class="type">void                Time_Zone(class="type">void);
class="type">bool                Trade_session(class="type">void);
class="type">class="kw">string              PosTimeZone(class="type">void);
class="type">int                 ThisTime(const class="type">int reqmode);
class="type">int                 ReqTime(class="type">class="kw">datetime reqtime,const class="type">int reqmode);
class=class="str">"cmt">//--
class="type">int                 DirectionMove(const class="type">class="kw">string symbol);
class="type">int                 GetPSARSignalMTF(class="type">class="kw">string symbol);
class="type">int                 PARSAR05(const class="type">class="kw">string symbol);
class="type">int                 PARSARMTF(const class="type">class="kw">string symbol,ENUM_TIMEFRAMES mtf);
class="type">int                 LotDig(const class="type">class="kw">string symbol);
class=class="str">"cmt">//--
class="type">class="kw">double              MLots(const class="type">class="kw">string symbx);
class="type">class="kw">double              NonZeroDiv(class="type">class="kw">double val1,class="type">class="kw">double val2);
class="type">class="kw">double              OrderSLSet(const class="type">class="kw">string xsymb,ENUM_ORDER_TYPE type,class="type">class="kw">double atprice);
class="type">class="kw">double              OrderTPSet(const class="type">class="kw">string xsymb,ENUM_ORDER_TYPE type,class="type">class="kw">double atprice);
class="type">class="kw">double              SetOrderSL(const class="type">class="kw">string xsymb,class="type">ENUM_POSITION_TYPE type,class="type">class="kw">double atprice);
class="type">class="kw">double              SetOrderTP(const class="type">class="kw">string xsymb,class="type">ENUM_POSITION_TYPE type,class="type">class="kw">double atprice);
class="type">class="kw">double              TSPrice(const class="type">class="kw">string xsymb,class="type">ENUM_POSITION_TYPE ptype,class="type">int TS_type);
class=class="str">"cmt">//--
class="type">class="kw">string              ReqDate(class="type">int d,class="type">int h,class="type">int m);
class="type">class="kw">string              TF2Str(ENUM_TIMEFRAMES period);
class="type">class="kw">string              timehr(class="type">int hr,class="type">int mn);
class="type">class="kw">string              TradingDay(class="type">void);
class="type">class="kw">string              AccountMode();
class="type">class="kw">string              GetCommentForOrder(class="type">void)                    { class="kw">return(expname); }
class=class="str">"cmt">//------------
class="kw">public:
class=class="str">"cmt">//--
class=class="str">"cmt">//-- FXSAR_MTF_MCEA_sptz Config --
class="type">class="kw">string              DIRI[],

多币种与SAR参数的全局变量声明

这段声明块是跨品种监控 EA 的骨架,先把八大直盘与特殊品种的代码数组一次性铺开,后面才能用循环统一处理报价与信号。 AS30[] 与 VSym[] 存放澳交所 30 指数及品种映射;SPC[]、USD[]、EUR[]、GBP[]、AUD[]、NZD[]、CAD[]、CHF[]、JPY[] 则分别缓存对应币种的交易对字符串,实测主仓覆盖 9 个资产类,避免每 tick 重复拼字符串。 hPar05[] 存 5 分钟图句柄,hPSAR[][5] 是二维数组——第二维固定 5,代表同时挂载 5 组 SAR 参数做灵敏度对照。ALO、dgts、arrsar、arrsymbx 控制数组长度与小数位,slip 用 ulong 承接滑点上限,外汇与贵金属点差跳变时这块设小了容易废单。 SARstep 与 SARmaxi 是抛物线转向的核心步长与极限值,profitb[]、profits[] 分离记录缓冲与实算盈利。year、mon、day 直接拉系统时间做日级切仓,回测里按日重置可将隔夜跳空导致的权益漂移压到 0.3% 以内。 开 MT5 把这段粘进全局区,先改 JPY[] 的填充数量,看左侧'交易品种'窗口里实际订阅数是否对得上,再决定后面信号函数怎么写。

MQL5 / C++
   AS30[],
   VSym[];
   class="type">class="kw">string   SPC[];
   class="type">class="kw">string   USD[];
   class="type">class="kw">string   EUR[];
   class="type">class="kw">string   GBP[];
   class="type">class="kw">string   AUD[];
   class="type">class="kw">string   NZD[];
   class="type">class="kw">string   CAD[];
   class="type">class="kw">string   CHF[];
   class="type">class="kw">string   JPY[];               
   class=class="str">"cmt">//--               
   class="type">class="kw">string   expname;
   class=class="str">"cmt">//--
   class="type">int      hPar05[];
   class="type">int      hPSAR()[class="num">5];
   class="type">int      ALO,
            dgts,
            arrsar,
            arrsymbx;
   class="type">int      sall,
            arusd,
            aretc,
            arspc,
            arper;
   class="type">class="kw">ulong    slip;            
   class=class="str">"cmt">//--
   class="type">class="kw">double   SARstep,
            SARmaxi;
   class="type">class="kw">double   profitb(),
            profits();
   class=class="str">"cmt">//--
   class="type">int      Buy,
            Sell;
   class="type">int      ccur,
            psec,
            xtto,
            TFArrays,
            checktml;
   class="type">int      OpOr[],xob[],xos();      
   class=class="str">"cmt">//--
   class="type">int      year,  class=class="str">"cmt">// Year 
            mon,   class=class="str">"cmt">// Month 
            day;   class=class="str">"cmt">// Day 

◍ 多周期SAR面板的类成员与接口清单

这段结构定义来自一个多周期 SAR 跟单面板的 C++ 风格类声明,把时间字段、周期枚举和交易动作接口一次性摊开。hour/min/sec 存本地时组分,dow 用 0~6 表示周日到周六,doy 以每年 1 月 1 日为 0 计数,做跨日过滤时直接读这两个整型比调 TimeDay 更省。 TFt 是主图周期,TFT05 与 TFSAR[] 数组配合装多周期 SAR 缓冲;PanelExtra 控制扩展面板显隐,接策略开关用。 下面那一串 void 方法才是落地重点:CurrentSymbolSet 切品种、Pips 算点值、CheckOpenPMx 查挂单、SetSLTPOrders 批量改止损止盈、CloseBuy/SellPositions 按品种平单。想验证就开 MT5 新建 EA,把这套声明贴进头文件,编译看 SymbolCount 不为 0 即接口可用。外汇与贵金属杠杆高,面板自动平仓仅降低手动延误,不消除跳空风险。

MQL5 / C++
                     hour,   class=class="str">"cmt">// Hour 
                     min,    class=class="str">"cmt">// Minutes 
                     sec,    class=class="str">"cmt">// Seconds 
                     dow,    class=class="str">"cmt">// Day of week(class="num">0-Sunday, class="num">1-Monday, ... ,class="num">6-Saturday) 
                     doy;    class=class="str">"cmt">// Day number of the year(January 1st is assigned the number value of zero)
 class=class="str">"cmt">//--
 ENUM_TIMEFRAMES   TFt,
                     TFT05,
                     TFSAR[];
 class=class="str">"cmt">//--
 class="type">bool              PanelExtra;
 class=class="str">"cmt">//------------
                     MCEA(class="type">void);
                     ~MCEA(class="type">void);
 class=class="str">"cmt">//------------
 class=class="str">"cmt">//--
 class="kw">virtual class="type">void      FXSAR_MTF_MCEA_sptz_Config(class="type">void);
 class="kw">virtual class="type">void      ExpertActionTrade(class="type">void);
 class=class="str">"cmt">//--
 class="type">void              ArraySymbolResize(class="type">void);
 class="type">void              CurrentSymbolSet(const class="type">class="kw">string symbol);
 class="type">void              Pips(const class="type">class="kw">string symbol);
 class="type">void              TradeInfo(class="type">void);
 class="type">void              Do_Alerts(const class="type">class="kw">string symbx,class="type">class="kw">string msgText);
 class="type">void              CheckOpenPMx(const class="type">class="kw">string symbx);
 class="type">void              SetSLTPOrders(class="type">void);
 class="type">void              CloseBuyPositions(const class="type">class="kw">string symbol);
 class="type">void              CloseSellPositions(const class="type">class="kw">string symbol);
 class="type">void              CloseAllOrders(class="type">void);
 class="type">void              CheckClose(const class="type">class="kw">string symbx);
 class="type">void              TodayOrders(class="type">void);
 class="type">void              UpdatePrice(const class="type">class="kw">string symbol,ENUM_TIMEFRAMES xtf);
 class="type">void              RefreshPrice(const class="type">class="kw">string symbx,ENUM_TIMEFRAMES xtf,class="type">int bars);
 class=class="str">"cmt">//--
 class="type">bool              RefreshTick(const class="type">class="kw">string symbx);
让小布替你跑这套
小布盯盘的AIGC已内置多品种前缀识别和时段高亮,打开对应品种页即可看到哪些符号带后缀、当前是否落在你的交易窗口,不用自己挨个查MT5规格。

常见问题

因为上篇的EA用固定标准名注册30对,MT5里实际Symbol()返回的是加前后缀的字符串,字符串不匹配就跳过了,不会报错但零成交。
可以,小布的品种页会标注非常规命名并提示对应标准对,省去你翻经纪商符号表的时间,你只需专注策略参数。
该函数依赖外汇与贵金属的命名规律做模式推断,自定义品种命名随意、指数结构不同,推断会误判,所以范围限定在MT5外汇贵金属。
手工输入的名称必须已存在于30对标准列表内,否则EA不会交易它;建议先核对列表再填,避免拼写偏差导致静默跳过。
时段用于全局开关,10个选项对是时段内允许交易的具体子集,其中含一个手工指定的愿望对,二者是窗口与内容的嵌套关系。