如何利用 MQL5 创建简单的多币种智能交易系统(第 5 部分):凯尔特纳(Keltner)通道上的布林带  指标信号·进阶篇
📘

如何利用 MQL5 创建简单的多币种智能交易系统(第 5 部分):凯尔特纳(Keltner)通道上的布林带 指标信号·进阶篇

第 2/3 篇

「止损下移的触发与价格归一」

这段逻辑只干一件事:在多头浮盈足够时,把止损向入场价上方挪、止盈按最小 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 跑一遍看成交回执。

MQL5 / C++
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 的口子。

MQL5 / C++
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 这类宏。

MQL5 / C++
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% 在黄金跳空时可能一天扫掉大半权益。

MQL5 / C++
   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,能直接避开流动性最差的开周末时段。

MQL5 / C++
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 回测曲线是否更平。

MQL5 / C++
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

常见问题

用价格归一化比较通道位移幅度,只在收盘跌破归一阈值才下移止损,避免噪音触发。
把品种池和时段写成枚举与输入参数,在EA面板下拉选择即可,不需动底层逻辑。
可以,小布能按你设定的品种池和时间窗汇总各币种通道信号与止损状态,省去手动翻盘。
将出场阈值、提醒开关、星期锁全部放进输入面板分组,开局一次填完后续免调。
把交易时段与星期枚举写进参数并默认禁用周一早盘,EA会按设定跳过非允许时间。