如何利用 MQL5 创建简单的多币种智能交易系统(第 2 部分):指标信号:多时间帧抛物线 SAR 指标·进阶篇
(2/3)· 单一 iSAR 指标跨 M15 到 D1 五周期,如何驱动 28 外汇对加金银行情的自动开平
EA 订单风控与通知的参数入口
把一套 MT5 EA 的止损、止盈、移动止损和信号反手逻辑全部暴露成 input 组,是实盘前必须核对的一步。下面这段声明直接定义了交易与订单管理的 15 个外部参数,改一个值就可能改变整组持仓的退出方式。 [CODE]input group "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter input YN use_sl = No; // Use Order Stop Loss (Yes) or (No) input YN autosl = Yes; // Use Automatic Calculation Stop Loss (Yes) or (No) input double SLval = 30; // If Not Use Automatic SL - Input SL value in Pips input YN use_tp = Yes; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 10; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input YN autotrl = Yes; // Use Automatic Trailing (Yes) or (No) input double TSval = 5; // If Not Use Automatic Trailing Input Trailing value in Pips input double TSmin = 5; // Minimum Pips to start Trailing Stop input double TPmin = 25; // Input Trailing Profit Value in Pips input YN Close_by_Opps = Yes; // Close Trade By Opposite Signal (Yes) or (No) input YN SaveOnRev = Yes; // Close Trade and Save profit due to weak signal (Yes) or (No) //--Others Expert Advisor Parameter input group "=== Others Expert Advisor Parameter ==="; // Others EA Parameter input YN alerts = Yes; // Display Alerts / Messages (Yes) or (No) input YN UseEmailAlert = No; // Email Alert (Yes) or (No) input YN UseSendnotify = No; // Send Notification (Yes) or (No) input YN trade_info_display = Yes; // Select Display Trading Info on Chart (Yes) or (No)[/CODE] 逐行拆解:前 14 行归在「Trade & Order management Parameter」组里。use_sl 默认 No 代表下单不挂静态止损,但 autosl=Yes 表示若开启自动计算仍可能动态补止损;SLval=30 仅在 autosl=No 时生效,单位为标准点。use_tp 与 autotp 同为 Yes,TPval=10 是自动关闭时的备用止盈点数。 移动止损块里 TrailingSLTP=Yes 且 autotrl=Yes,TSval=5 为回撤触发距离,TSmin=5 是启动所需最小点数,TPmin=25 则是锁利阈值。Close_by_Opps=Yes 让反向信号平掉原有单,SaveOnRev=Yes 在弱信号时落袋。 其余 EA 参数组控制提示:alerts=Yes 在图表弹消息,UseEmailAlert 与 UseSendnotify 均 No 不发邮件和手机推送,trade_info_display=Yes 在图上显示交易信息。外汇与贵金属杠杆高,参数误设可能在几分钟内放大亏损,挂载前建议先在策略测试器用 2023 年 XAUUSD 的 M15 数据跑一遍验证退出逻辑。
class="kw">input group "=== Trade & Order management Parameter ==="; class=class="str">"cmt">// Trade & Order management Parameter class="kw">input YN use_sl = No; class=class="str">"cmt">// Use Order Stop Loss(Yes) or(No) class="kw">input YN autosl = Yes; class=class="str">"cmt">// Use Automatic Calculation Stop Loss(Yes) or(No) class="kw">input class="type">class="kw">double SLval = class="num">30; class=class="str">"cmt">// If Not Use Automatic SL - Input SL value in Pips class="kw">input YN use_tp = Yes; class=class="str">"cmt">// Use Order Take Profit(Yes) or(No) class="kw">input YN autotp = Yes; class=class="str">"cmt">// Use Automatic Calculation Take Profit(Yes) or(No) class="kw">input class="type">class="kw">double TPval = class="num">10; class=class="str">"cmt">// If Not Use Automatic TP - Input TP value in Pips class="kw">input YN TrailingSLTP = Yes; class=class="str">"cmt">// Use Trailing SL/TP(Yes) or(No) class="kw">input YN autotrl = Yes; class=class="str">"cmt">// Use Automatic Trailing(Yes) or(No) class="kw">input class="type">class="kw">double TSval = class="num">5; class=class="str">"cmt">// If Not Use Automatic Trailing Input Trailing value in Pips class="kw">input class="type">class="kw">double TSmin = class="num">5; class=class="str">"cmt">// Minimum Pips to start Trailing Stop class="kw">input class="type">class="kw">double TPmin = class="num">25; class=class="str">"cmt">// Input Trailing Profit Value in Pips class="kw">input YN Close_by_Opps = Yes; class=class="str">"cmt">// Close Trade By Opposite Signal(Yes) or(No) class="kw">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 class="kw">input group "=== Others Expert Advisor Parameter ==="; class=class="str">"cmt">// Others EA Parameter class="kw">input YN alerts = Yes; class=class="str">"cmt">// Display Alerts / Messages(Yes) or(No) class="kw">input YN UseEmailAlert = No; class=class="str">"cmt">// Email Alert(Yes) or(No) class="kw">input YN UseSendnotify = No; class=class="str">"cmt">// Send Notification(Yes) or(No) class="kw">input YN trade_info_display = Yes; class=class="str">"cmt">// Select Display Trading Info on Chart(Yes) or(No)
◍ EA 类里的私有变量先铺开
这段 MQL5 把整个策略状态塞进了一个叫 MCEA 的类,而且全放在 private 段。magicEA 设成 2023102,是 EA 在 MT5 订单池里认领自己仓位的 ID,回测或实盘里用 OrderMagicNumber 过滤时靠它区分别的程序。 类里第一组变量是时间拆解:x_year、x_mon 一直到 x_sec,把当前 tick 的时间拆成 6 个整型。做时段过滤(比如只在伦敦段 8–16 点干活)时,直接读这几个值比反复调 TimeCurrent 再算结构体更省事。 价格与仓位相关的 double 有 OPEN/HIGH/LOW/CLOSE 四个数组加 TIME、closetime。注意 OPEN[] 这些没写大小,后面得用 ArrayResize 或绑定指标缓冲,否则首根 K 线就越界报错。外汇和贵金属波动大,这类数组越界在 EURUSD 跳空时容易把 EA 挂掉,开 MT5 跑之前先确认拷贝逻辑。 下面逐行看声明:
class="kw">input class="type">ulong magicEA = class="num">2023102; class=class="str">"cmt">// Expert ID(Magic Number) class=class="str">"cmt">//--- class=class="str">"cmt">//+------------------------------------------------------------------+ 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="type">int posCur1, posCur2; 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">//------------
「EA 接口与多周期 SAR 句柄的声明骨架」
这段声明集中暴露了一个 MTF 抛物线 SAR 系统的对外接口与内部状态容器。从函数签名看,DirectionMove 与 GetPSARSignalMTF 都接收 symbol 参数,说明信号判定是按品种隔离的,而不是全局单例。 PARSARMTF 多带一个 ENUM_TIMEFRAMES 参数,配合 hPSAR[][5] 这个二维句柄数组,能推断程序把 M15 到 D1 共 5 个周期各存一列指标句柄。hPar05[] 则单独承载 M5 的 iSAR 句柄,这种拆分意味着 M5 被当作触发层、更高周期作过滤层。 LotDig 与 MLots 返回 double,负责把品种报价精度转成可下单数;OrderSLSet / SetOrderSL 等分类型与持仓类型双签名,说明开仓挂单与持仓改止损走两套入口。GetCommentForOrder 直接 return expname,订单注释写死在 expname 成员里。 想在 MT5 里复刻,可先把 hPSAR 第二维固定为 5,对应 M15、M30、H1、H4、D1 五个周期,避免越界。外汇与贵金属杠杆高,多周期信号共振也不代表胜率必然提升,回测时须自行统计各周期权重。
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">//-- FXSAR_MTF_MCEA Config -- class="type">class="kw">string DIRI[], AS30[]; class="type">class="kw">string expname; class="type">int hPar05[]; class=class="str">"cmt">// Handle for the iSAR indicator for M5 Timeframe class="type">int hPSAR[][class="num">5]; class=class="str">"cmt">// Handle Indicator, where each Symbol has class="num">5 arrays for Timeframe starting from TF_M15 to TF_D1 class="type">int ALO, dgts, arrsar,
EA 全局变量的声明骨架
多周期 SAR 策略的 EA 类里,先把所有跨周期、跨品种和交易控制用的变量一次性摊开,后面才谈得上逻辑。下面这段声明直接决定了你能同时盯几个品种、几个周期。 sall 与 arper 是品种数组和周期参数的整数容器,slip 用 ulong 承接滑点控制;SARstep、SARmaxi 则是抛物线 SAR 的步长与极值参数,profitb[]、profits[] 分别存多空双边的历史利润序列。 时间维度拆得很细:year 到 sec 是标准时间分量,dow 用 0~6 表示周日到周六,doy 把 1 月 1 日记为 0。做时段过滤时,这些字段比直接调 TimeCurrent 更省事。 周期方面,TFt 是当前主周期,TFT05 是固定的 M5 参考,TFSAR[] 是 SAR 要计算的多周期数组;PanelExtra 控制面板扩展显示。构造函数 MCEA(void) 与析构 ~MCEA(void) 之外,FXSAR_MTF_MCEA_Config 做参数初始化,ExpertActionTrade 跑交易决策,ArraySymbolResize 和 CurrentSymbolSet 负责品种数组扩容与当前品种绑定。 把这些变量原样拷进 MT5 头文件,编译期就能看出你准备跑几个符号、几个 TF——若 TFSAR[] 长度写死为 3,那多周期就只认 3 个周期,改之前先想清楚回测覆盖度。
arrsymbx; class="type">int sall, arper; class="type">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 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="kw">virtual class="type">void FXSAR_MTF_MCEA_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);
◍ EA 内部函数清单怎么读
这段声明集中暴露了一个 MT5 半自动 EA 的核心能力边界:它既能下单(OpenBuy / OpenSell),也能按品种批量平仓(CloseBuyPositions / CloseSellPositions / CloseAllOrders),还内置了当日交易开关 TradingToday 与盈利单清理 CloseAllProfit。
从返回类型能反推调用风险:void 类函数(如 Do_Alerts、SetSLTPOrders)执行失败也不会给布尔反馈,调试时只能靠 Print 或日志;bool 类(如 ModifyOrderSLTP、RefreshTick)才适合写 if(!func()) { /* 处理 */ } 的容错分支。
int 类里 PairsIdxArray 与 TFIndexArray 是把「品种名 / 周期」映射成数组下标的工具,意味着 EA 大概率维护了一张多品种多周期矩阵,而不是单图表硬算。外汇与贵金属杠杆高,这类批量平仓函数若在滑点扩大时触发,可能瞬间吃掉当日浮盈,上 MT5 前务必用策略测试器跑一遍品种样本。
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); class="type">bool TradingToday(class="type">void); class="type">bool OpenBuy(const class="type">class="kw">string symbol); class="type">bool OpenSell(const class="type">class="kw">string symbol); class="type">bool ModifyOrderSLTP(class="type">class="kw">double mStop,class="type">class="kw">double ordtp); class="type">bool ModifySLTP(const class="type">class="kw">string symbx,class="type">int TS_type); class="type">bool CloseAllProfit(class="type">void); class="type">bool ManualCloseAllProfit(class="type">void); class=class="str">"cmt">//-- class="type">int PairsIdxArray(const class="type">class="kw">string symbol); class="type">int TFIndexArray(ENUM_TIMEFRAMES TF); class="type">int GetOpenPosition(const class="type">class="kw">string symbol); class="type">int GetCloseInWeakSignal(const class="type">class="kw">string symbol,class="type">int exis); class="type">int ThisTime(const class="type">int reqmode); class=class="str">"cmt">//-- class="type">class="kw">string getUninitReasonText(class="type">int reasonCode);
「把 30 个货币对塞进多周期 SAR 监控」
这段初始化收尾把前面类定义真正落地:在 OnInit 里只调一句 FXSAR_MTF_MCEA_Config,EA 加载即完成全部品种与周期句柄的装配,返回 INIT_SUCCEEDED 后不再做多余动作。 配置函数先硬编码了 30 个交易标的,含七大直盘、交叉盘以及 XAUUSD、XAGUSD 两个贵金属对;ArraySize 取到 sall=30,据此给 AS30 和 DIRI 扩容并整组拷贝,再循环 SymbolSelect 把它们在 MT5 市场报价窗强制可见,否则后续 iSAR 取不到数据。 多周期部分用 TFA 数组列了 M15 到 D1 五档周期,TFArrays=5;TFSAR 拷贝后,TFt 直接取索引 2 即 H1 作为主判周期。M5 的 SAR 句柄则在双层循环里按 hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi) 逐个品种生成,SARstep 与 SARmaxi 为类内成员参数,未在此赋值。 外汇与贵金属杠杆品种跳空频繁,SAR 加速因子若沿用默认 0.02/0.2,在 XAUUSD 上反转信号可能滞后于实体波动,建议开 MT5 把这两常量提出来单独试 0.01/0.15 的钝化组合。
class=class="str">"cmt">//------------ class=class="str">"cmt">//--- }; class=class="str">"cmt">//-end class MCEA class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit(class="type">void) { class=class="str">"cmt">//--- mc.FXSAR_MTF_MCEA_Config(); class=class="str">"cmt">//-- class="kw">return(INIT_SUCCEEDED); class=class="str">"cmt">//--- } class=class="str">"cmt">//-end OnInit() class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert Configuration | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void MCEA::FXSAR_MTF_MCEA_Config(class="type">void) { class=class="str">"cmt">//--- class=class="str">"cmt">//-- class="type">class="kw">string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP", "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD", "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF", "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; class=class="str">"cmt">// class="num">30 pairs class=class="str">"cmt">//-- sall=ArraySize(All30); ArrayResize(AS30,sall,sall); ArrayCopy(AS30,All30,class="num">0,class="num">0,WHOLE_ARRAY); class=class="str">"cmt">//-- arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,class="num">0,class="num">0,WHOLE_ARRAY); for(class="type">int x=class="num">0; x<arrsymbx; x++) {SymbolSelect(DIRI[x],true);} pairs="Multi Currency class="num">30 Pairs"; class=class="str">"cmt">//-- TFT05=PERIOD_M5; ENUM_TIMEFRAMES TFA[]={PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1}; TFArrays=ArraySize(TFA); ArrayResize(TFSAR,TFArrays,TFArrays); ArrayCopy(TFSAR,TFA,class="num">0,class="num">0,WHOLE_ARRAY); class=class="str">"cmt">//-- TFt=TFSAR[class="num">2]; class=class="str">"cmt">//-- class=class="str">"cmt">//-- iSAR Indicators handle for all symbol for(class="type">int x=class="num">0; x<arrsymbx; x++) { hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi); class=class="str">"cmt">//-- Handle for the iSAR indicator for M5 Timeframe class=class="str">"cmt">//--