如何利用 MQL5 创建简单的多币种智能交易系统(第 5 部分):凯尔特纳(Keltner)通道上的布林带 指标信号·进阶篇
「止损下移的触发与价格归一」
这段逻辑只干一件事:在多头浮盈足够时,把止损向入场价上方挪、止盈按最小 TP 距离重算。先记下两个本地变量,modselsl 直接接 vtrss(通常是某档追踪止损参考值),modseltp 则用品种对象做点值归一:price - TPmin*pip 再 NormalizePrice,避免 XAUUSD 这类 3 位小数品种算出的价格拒单。 bool modsel 的判定很硬:当前 price 必须低于 modminsl,且候选止损 modselsl 小于 modstart(初始止损),同时账户里该单原有止损为 0 或原止损比候选更靠下。三层 AND 少一层都不会改单。 真正发单还得过 netp>0.05 这道闸——净仓位占比大于 5% 才允许调,防止迷你仓乱改。过了就调 mc_trade.PositionModify,返回结果写回 modist。外汇与贵金属杠杆高,这类自动移损若 pip 倍数设错,可能在数据行情瞬间把止损扫在不利位,建议先在 MT5 策略测试器用 2023 年 XAUUSD M15 跑一遍看成交回执。
class="type">class="kw">double modselsl=vtrss; class="type">class="kw">double modseltp=mc_symbol.NormalizePrice(price-TPmin*pip); class="type">bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==class="num">0.0||modselsl<pos_stop)); class=class="str">"cmt">//-- if(modsel && netp>class="num">0.05) { modist=mc_trade.PositionModify(symbol,modselsl,modseltp); } } } } class=class="str">"cmt">//-- class="kw">return(modist); class=class="str">"cmt">//--- } class=class="str">"cmt">//-end ModifySLTP() class=class="str">"cmt">//---------//
把多币种 EA 的骨架搭进 MT5
做多币种系统化交易,第一步是把品种、时段和指标句柄在初始化阶段就安排明白。EA 输入里留了『智能系统时间帧』用来算信号,凯尔特纳通道和布林带的参数直接透传,不另起炉灶;品种则从预设的 10 个选项里挑,默认覆盖 30 个外汇对。品种名带前缀后缀也不要紧,HandlingSymbolArrays() 会调 SetSymbolNamePS() 做归一,拼错的话 EA 会报警并自删,不跟你含糊。 时段控制是这块的硬骨头。除了自定义的小时分钟,新西兰到纽约五大时段都由 EA 内部推算起止,交易者只管选枚举。OnInit() 里最先跑的是 BBOnKeltnerChannel_MCEA_Config(),代码 468–484 行专门建各指标句柄,TF 被限制从 M5 到 D1,再宽就超出设计边界了。 [CODE] 里是头文件和时区枚举的落地样子:Trade.mqh 等四个标准库先 include,CTrade、CSymbolInfo 等四个对象随后实例化;tm_zone 枚举把六大交易会话写成 Cus_Session 到 US_New_York,你在输入面板选哪个,后面 Trade_session() 就按哪个布尔返回。 OnTick() 只干一件事——调 ExpertActionTrade()。这个函数顺完定期开关(周日到周六可逐日禁交易)和时段布尔后,才进开平仓逻辑;Trade_session() 为 false 时,EA 不新开仓,只做疲软平仓和尾随止损,相当于『只看护不进攻』模式。 信号来自 GetOpenPosition() → BBOnKeltnerChannel() → PairsIdxArray()。后者按品种名取句柄,把凯尔特纳中线/上轨/下轨(缓冲 0/1/2)和布林 BASE/UPPER/LOWER(同样 0/1/2)拷进数组,且布林的应用价格直接用了凯尔特纳句柄。返回 1 调 OpenBuy()、-1 调 OpenSell()、0 不动——外汇和贵金属杠杆高,信号只是概率倾向,真跑起来请在策略测试器先过一遍。 图表交互别忽视。『M』弹手动面板能批量挂止损止盈或全平;『C』切品种,背后是 OnChartEvent() 调 ChangeChartSymbol();『R』一键移除 EA。这三颗按钮让多币种 EA 在盯盘时仍留了人工 override 的口子。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Include | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include <Trade\Trade.mqh> class="macro">#include <Trade\PositionInfo.mqh> class="macro">#include <Trade\SymbolInfo.mqh> class="macro">#include <Trade\AccountInfo.mqh> class=class="str">"cmt">//-- CTrade mc_trade; CSymbolInfo mc_symbol; CPositionInfo mc_position; CAccountInfo mc_account; class=class="str">"cmt">//--- class=class="str">"cmt">//-- enum tm_zone { Cus_Session, class=class="str">"cmt">// Trading on Custom Session New_Zealand, class=class="str">"cmt">// Trading on New Zealand Session Australia, class=class="str">"cmt">// Trading on Australia Sydney Session Asia_Tokyo, class=class="str">"cmt">// Trading on Asia Tokyo Session Europe_London, class=class="str">"cmt">// Trading on Europe London Session US_New_York class=class="str">"cmt">// Trading on US New York Session }; class=class="str">"cmt">//-- class=class="str">"cmt">//-- enum swhour {
◍ 把时间窗和品种池写成枚举
做跨周期扫描时,最忌讳把小时、分钟、品种直接硬编码进判断逻辑。下面这套枚举把 0–23 点逐小时映射成 hr_00 到 hr_23,数值与服务器时间小时数一一对应,回测时切时段只改枚举引用即可。 分钟维度另起 inmnt 枚举,只取 0/5/10…55 这 12 个整五分节点,配合 H1 以上周期做触发,能避开中间噪音棒。 PairsTrade 枚举把可交易范围分成 All30、Usds、Eurs 等 10 类,实盘跑 EURUSD 就选 Eurs,跑全 30 主要外汇对就选 All30;外汇与贵金属杠杆高、滑点跳空频繁,枚举只是缩小扫描面,不替代风控。 YN 和 TFUSE 两个小枚举分别管开关与周期:TFUSE 覆盖 M5 到 H4 共 7 档,EA 初始化时读一个 TFUSE 值就能决定主图周期,不用满屏写 PERIOD_H1 这类宏。
hr_00=class="num">0, class=class="str">"cmt">// class="num">00:class="num">00 hr_01=class="num">1, class=class="str">"cmt">// class="num">01:class="num">00 hr_02=class="num">2, class=class="str">"cmt">// class="num">02:class="num">00 hr_03=class="num">3, class=class="str">"cmt">// class="num">03:class="num">00 hr_04=class="num">4, class=class="str">"cmt">// class="num">04:class="num">00 hr_05=class="num">5, class=class="str">"cmt">// class="num">05:class="num">00 hr_06=class="num">6, class=class="str">"cmt">// class="num">06:class="num">00 hr_07=class="num">7, class=class="str">"cmt">// class="num">07:class="num">00 hr_08=class="num">8, class=class="str">"cmt">// class="num">08:class="num">00 hr_09=class="num">9, class=class="str">"cmt">// class="num">09:class="num">00 hr_10=class="num">10, class=class="str">"cmt">// class="num">10:class="num">00 hr_11=class="num">11, class=class="str">"cmt">// class="num">11:class="num">00 hr_12=class="num">12, class=class="str">"cmt">// class="num">12:class="num">00 hr_13=class="num">13, class=class="str">"cmt">// class="num">13:class="num">00 hr_14=class="num">14, class=class="str">"cmt">// class="num">14:class="num">00 hr_15=class="num">15, class=class="str">"cmt">// class="num">15:class="num">00 hr_16=class="num">16, class=class="str">"cmt">// class="num">16:class="num">00 hr_17=class="num">17, class=class="str">"cmt">// class="num">17:class="num">00 hr_18=class="num">18, class=class="str">"cmt">// class="num">18:class="num">00 hr_19=class="num">19, class=class="str">"cmt">// class="num">19:class="num">00 hr_20=class="num">20, class=class="str">"cmt">// class="num">20:class="num">00 hr_21=class="num">21, class=class="str">"cmt">// class="num">21:class="num">00 hr_22=class="num">22, class=class="str">"cmt">// class="num">22:class="num">00 hr_23=class="num">23 class=class="str">"cmt">// class="num">23:class="num">00 }; class=class="str">"cmt">//-- class=class="str">"cmt">//-- enum inmnt { mn_00=class="num">0, class=class="str">"cmt">// Minute class="num">0 mn_05=class="num">5, class=class="str">"cmt">// Minute class="num">5 mn_10=class="num">10, class=class="str">"cmt">// Minute class="num">10 mn_15=class="num">15, class=class="str">"cmt">// Minute class="num">15 mn_20=class="num">20, class=class="str">"cmt">// Minute class="num">20 mn_25=class="num">25, class=class="str">"cmt">// Minute class="num">25 mn_30=class="num">30, class=class="str">"cmt">// Minute class="num">30 mn_35=class="num">35, class=class="str">"cmt">// Minute class="num">35 mn_40=class="num">40, class=class="str">"cmt">// Minute class="num">40 mn_45=class="num">45, class=class="str">"cmt">// Minute class="num">45 mn_50=class="num">50, class=class="str">"cmt">// Minute class="num">50 mn_55=class="num">55 class=class="str">"cmt">// Minute class="num">55 }; class=class="str">"cmt">//-- class=class="str">"cmt">//-- enum PairsTrade { All30, class=class="str">"cmt">// All Forex class="num">30 Pairs TrdWi, class=class="str">"cmt">// Trader Wishes Pairs Usds, class=class="str">"cmt">// Forex USD Pairs Eurs, class=class="str">"cmt">// Forex EUR Pairs Gbps, class=class="str">"cmt">// Forex GBP Pairs Auds, class=class="str">"cmt">// Forex AUD Pairs Nzds, class=class="str">"cmt">// Forex NZD Pairs Cads, class=class="str">"cmt">// Forex CDD Pairs Chfs, class=class="str">"cmt">// Forex CHF Pairs Jpys class=class="str">"cmt">// Forex JPY Pairs }; class=class="str">"cmt">//-- class=class="str">"cmt">//-- enum YN { No, Yes }; class=class="str">"cmt">//-- class=class="str">"cmt">//-- enum TFUSE { TFM5, class=class="str">"cmt">// PERIOD_M5 TFM15, class=class="str">"cmt">// PERIOD_M15 TFM30, class=class="str">"cmt">// PERIOD_M30 TFH1, class=class="str">"cmt">// PERIOD_H1 TFH2, class=class="str">"cmt">// PERIOD_H2 TFH3, class=class="str">"cmt">// PERIOD_H3 TFH4 class=class="str">"cmt">// PERIOD_H4
「把多周期与通道参数一次性塞进EA输入面板」
这段声明把策略要用的非标准周期和通道指标全部前置成 input 参数,开 MT5 后能在属性框直接改,不必动代码。注意 TFH6/TFH8/TFH12 是自定义枚举值,对应 PERIOD_H6、PERIOD_H8、PERIOD_H12,MT5 原生周期里没有这仨,得靠外部 period 转换或自定义 timeframe 库才能跑通。 Keltner 通道默认周期 20、ATR 周期也 20、带宽乘子 1.0,均线用 EMA 且取典型价(PRICE_TYPICAL);布林带周期给到 38、标准差 1.0,这两组参数组合在欧美盘重叠时段对均值回归类信号倾向更敏感。 交易品种用枚举 All30 配合字符串白名单 traderwishes(如 "eurusd,usdchf"),还留了 sym_prefix / sym_suffix 应对券商后缀(比如 .pro、m.)。外汇与贵金属杠杆高,参数全开 All30 时同屏占用计算资源可能翻倍,先挑 3~5 对验证再扩。 资金管理只暴露一个 Risk 浮点,范围 1.0%~10.0%,配合 DynamLot 做动态手数;真要上实盘,建议从 1.0% 起测,10% 在黄金跳空时可能一天扫掉大半权益。
TFH6, class=class="str">"cmt">// PERIOD_H6 TFH8, class=class="str">"cmt">// PERIOD_H8 TFH12, class=class="str">"cmt">// PERIOD_H12 TFD1 class=class="str">"cmt">// PERIOD_D1 }; class=class="str">"cmt">//-- class=class="str">"cmt">//--- class="kw">input group "=== Global Strategy EA Parameter ==="; class=class="str">"cmt">// Global Strategy EA Parameter class="kw">input TFUSE tfinuse = TFH1; class=class="str">"cmt">// Select Expert TimeFrame, class="kw">default PERIOD_H1 class="kw">input class="type">int KCPeriod = class="num">20; class=class="str">"cmt">// Input Keltner Channel Period, class="kw">default class="num">20 class="kw">input ENUM_MA_METHOD KCMethod = MODE_EMA; class=class="str">"cmt">// Select Keltner Channel MA Method, class="kw">default EMA class="kw">input ENUM_APPLIED_PRICE KCMAAP = PRICE_TYPICAL; class=class="str">"cmt">// Select Keltner Channel MA Applied Price, class="kw">default Price Typical class="kw">input class="type">int KCATRPer = class="num">20; class=class="str">"cmt">// Input Keltner Channel ATR Period, class="kw">default class="num">20 class="kw">input class="type">class="kw">double KCATRBandsMulti = class="num">1.0; class=class="str">"cmt">// Input Keltner Channel ATR bands multiplier class="kw">input class="type">int BBPeriod = class="num">38; class=class="str">"cmt">// Input Bollinger Bands® Indicator period, class="kw">default class="num">38 class="kw">input class="type">class="kw">double BBDevi = class="num">1.0; class=class="str">"cmt">// Input Bollinger Bands® Indicator Deviations, class="kw">default class="num">1.00 class=class="str">"cmt">//--- class="kw">input group "=== Select Pairs to Trade ==="; class=class="str">"cmt">// Selected Pairs to trading class="kw">input PairsTrade usepairs = All30; class=class="str">"cmt">// Select Pairs to Use class="kw">input class="type">class="kw">string traderwishes = "eg. eurusd,usdchf"; class=class="str">"cmt">// If Use Trader Wishes Pairs, class="kw">input pair name here, separate by comma class="kw">input class="type">class="kw">string sym_prefix = ""; class=class="str">"cmt">// Input the symbol prefix in case sensitive(if any) class="kw">input class="type">class="kw">string sym_suffix = ""; class=class="str">"cmt">// Input the symbol suffix in case sensitive(if any) class=class="str">"cmt">//-- class="kw">input group "=== Money Management Lot Size Parameter ==="; class=class="str">"cmt">// Money Management Lot Size Parameter class="kw">input mmt mmlot = DynamLot; class=class="str">"cmt">// Money Management Type class="kw">input class="type">class="kw">double Risk = class="num">10.0; class=class="str">"cmt">// Percent Equity Risk per Trade(Min=class="num">1.0% / Max=class="num">10.0%)
把交易时段和星期锁进EA参数
EA 跑不跑、什么时候跑,先靠输入参数卡死,而不是在策略逻辑里写死时间。下面这段声明把手动手数、指定时段开关、自定义会话起止、星期开关、止损开关全部暴露到 MT5 属性面板,改起来不用动核心代码。 注意默认配置:固定手数 0.01,自定义会话从 00:15 开到 23:55,周日周六关闭、周一至周五开启,止损默认不用但自动止损计算开着。外汇和贵金属波动大,0.01 手只是参数示例,实盘仓位请按账户净值自算,杠杆风险偏高。 [CODE] input double Lots = 0.01; // 手动固定手数 //--Trade on Specific Time input group "=== Trade on Specific Time ==="; // 分组标签:指定时间交易 input YN trd_time_zone = Yes; // 是否启用指定时区交易 input tm_zone session = Cus_Session; // 选择会话类型:自定义会话 input swhour stsescuh = hr_00; // 自定义会话起始小时(0-23) input inmnt stsescum = mn_15; // 自定义会话起始分钟(0-55) input swhour clsescuh = hr_23; // 自定义会话结束小时(0-23) input inmnt clsescum = mn_55; // 自定义会话结束分钟(0-55) //--Day Trading On/Off input group "=== Day Trading On/Off ==="; // 分组标签:按星期开关 input YN ttd0 = No; // 周日交易否 input YN ttd1 = Yes; // 周一交易 input YN ttd2 = Yes; // 周二交易 input YN ttd3 = Yes; // 周三交易 input YN ttd4 = Yes; // 周四交易 input YN ttd5 = Yes; // 周五交易 input YN ttd6 = No; // 周六交易否 //--Trade & Order management Parameter input group "=== Trade & Order management Parameter ==="; // 分组:订单管理 input YN use_sl = No; // 是否使用止损 input YN autosl = Yes; // 是否自动计算止损 [/CODE] 打开 MT5 导航器里的 EA 属性,把 Cus_Session 的起止改成你盯盘的活跃段(比如伦敦午盘 13:00–16:00),再把 ttd0/ttd6 保持 No,能直接避开流动性最差的开周末时段。
class="kw">input class="type">class="kw">double Lots = class="num">0.01; class=class="str">"cmt">// Input Manual Lot Size FixedLot class=class="str">"cmt">//--Trade on Specific Time class="kw">input group "=== Trade on Specific Time ==="; class=class="str">"cmt">// Trade on Specific Time class="kw">input YN trd_time_zone = Yes; class=class="str">"cmt">// Select If You Like to Trade on Specific Time Zone class="kw">input tm_zone session = Cus_Session; class=class="str">"cmt">// Select Trading Time Zone class="kw">input swhour stsescuh = hr_00; class=class="str">"cmt">// Time Hour to Start Trading Custom Session(class="num">0-class="num">23) class="kw">input inmnt stsescum = mn_15; class=class="str">"cmt">// Time Minute to Start Trading Custom Session(class="num">0-class="num">55) class="kw">input swhour clsescuh = hr_23; class=class="str">"cmt">// Time Hour to Stop Trading Custom Session(class="num">0-class="num">23) class="kw">input inmnt clsescum = mn_55; class=class="str">"cmt">// Time Minute to Stop Trading Custom Session(class="num">0-class="num">55) class=class="str">"cmt">//--Day Trading On/Off class="kw">input group "=== Day Trading On/Off ==="; class=class="str">"cmt">// Day Trading On/Off class="kw">input YN ttd0 = No; class=class="str">"cmt">// Select Trading on Sunday(Yes) or(No) class="kw">input YN ttd1 = Yes; class=class="str">"cmt">// Select Trading on Monday(Yes) or(No) class="kw">input YN ttd2 = Yes; class=class="str">"cmt">// Select Trading on Tuesday(Yes) or(No) class="kw">input YN ttd3 = Yes; class=class="str">"cmt">// Select Trading on Wednesday(Yes) or(No) class="kw">input YN ttd4 = Yes; class=class="str">"cmt">// Select Trading on Thursday(Yes) or(No) class="kw">input YN ttd5 = Yes; class=class="str">"cmt">// Select Trading on Friday(Yes) or(No) class="kw">input YN ttd6 = No; class=class="str">"cmt">// Select Trading on Saturday(Yes) or(No) class=class="str">"cmt">//--Trade & Order management Parameter 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)
◍ 把出场与提醒参数一次配齐
上面这组 input 把止损、止盈、移动止损和反向信号处理全暴露成外部参数,实盘前最好逐行过一遍,而不是用 EA 默认就直接挂。外汇和贵金属杠杆高,参数错配可能让单笔回撤超出预期,先用策略测试器跑历史段再上真仓。 SLval=30 代表不用自动止损时,手动给 30 点止损;use_tp 和 autotp 都设 Yes,说明止盈走自动测算,TPval=100 仅在 autotp=No 时生效。TrailingSLTP=Yes 配合 autotrl=Yes 走自动移动,TSval=5、TSmin=5、TPmin=25 意味着浮盈超 25 点且价格回撤 5 点就开始推损。 Close_by_Opps=Yes 让反向信号平掉原单,SaveOnRev=Yes 则在弱信号出现时锁利出场,这两条决定了你不会被震荡市反复打脸。alerts=Yes 但邮件和通知都关着,只看图表提示就够了;magicEA=20231204 是区分订单的魔术号,多 EA 同跑时必须不撞号。 period_kc=20 配 MODE_EMA 给 Keltner 通道做指数平滑,通道周期短了容易假突破,想降频就改 30 以上看 MT5 回测曲线是否更平。
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">100; 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) class="kw">input class="type">ulong magicEA = class="num">20231204; class=class="str">"cmt">// Expert ID(Magic Number) class=class="str">"cmt">//--- class=class="str">"cmt">//-- class="kw">input class="type">int period_kc = class="num">20; class=class="str">"cmt">// Input Keltner Channel Period class="kw">input ENUM_MA_METHOD ma_method = MODE_EMA; class=class="str">"cmt">// Select MA Type of smoothing