如何利用 MQL5 创建简单的多币种智能交易系统(第 6 部分):两条 RSI 指标相互交叉·进阶篇
📘

如何利用 MQL5 创建简单的多币种智能交易系统(第 6 部分):两条 RSI 指标相互交叉·进阶篇

第 2/3 篇

◍ 移动止损触发条件的代码骨架

这段逻辑是自动改单函数的核心判断分支,只在满足特定价格关系时才动手调止损止盈。

bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0modselsl<pos_stop)); 这一行先算一个布尔量:当前价低于模块最小止损线、候选止损小于初始止损、且持仓止损为空或候选止损更优。

if(modsel && netp>minprofit) 才是真正下单门槛——除了上面的价格条件,还必须保证净盈利大于最小利润阈值 minprofit,否则不碰仓位。 满足条件后只调一次 mc_trade.PositionModify(symbol,modselsl,modseltp),用候选止损和候选止盈改写持仓。外汇与贵金属杠杆高,这类自动改单在滑点行情中可能失效,建议在 MT5 策略测试器用 2023 年 XAUUSD 的 M15 数据跑一遍看触发频率。

MQL5 / C++
class="type">bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==class="num">0.0||modselsl<pos_stop));
class=class="str">"cmt">//--
if(modsel && netp>minprofit)
  {
   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">//---------//

「多币种 RSI 交叉 EA 的程序骨架与开仓逻辑」

这套多币种智能系统的输入层先靠一堆枚举把交易边界框死:时区、分钟、10 个可选品种、资金管理模式、指标计算周期都被限定在 M5 到 D1 之间。若 Magic Number 留空,EA 会顺手接管图表上的手工单,这点写 EA 时容易忽略,却直接决定谁在控单。 品种名处理走 HandlingSymbolArrays() → SetSymbolNamePS() 的调用链,后者专门兼容带前缀/后缀的经纪商符号(比如 mEURUSDp)。拼写错或验证不过,EA 会弹警告并自删,不会静默跑废单。 OnInit() 里必调的 RSIxRSI_MCEA_Config() 负责把品种、周期、指标句柄一次性建好;OnTick() 则只做一件事——调 ExpertActionTrade(),开平、尾随、止盈全塞在这一个函数里。时段开关由 Trade_session() 逐层下钻到 Time_Zone() 控制,默认开自定义时段,起止时分由交易者填。 开仓信号来自 GetOpenPosition():它先抓两个 RSI(快线 ma_period=10、慢线 ma_period=30,均用 PRICE_WEIGHTED)和 PSAR(0.02,0.2) 做过滤。返回 1 调 OpenBuy(),-1 调 OpenSell(),0 表示信号未明。快/慢 RSI 句柄的缓冲区编号都是 0,复制时别抄错序号。 图表上 M/C/R 三个按钮是给手工干预留的后门:M 出平仓与统一 SL/TP 面板,C 一键切品种,R 直接卸 EA。外汇与贵金属杠杆高,这类自动系统在任何时段都可能因滑点放大亏损,上 MT5 前先用策略测试器跑历史段验证句柄逻辑。

MQL5 / C++
class="macro">#include <Trade\Trade.mqh>
class="macro">#include <Trade\PositionInfo.mqh>
class="macro">#include <Trade\SymbolInfo.mqh>
class="macro">#include <Trade\AccountInfo.mqh>
CTrade         mc_trade;
CSymbolInfo    mc_symbol;
CPositionInfo  mc_position;
CAccountInfo   mc_account;
enum tm_zone
{
   Cus_Session,       class=class="str">"cmt">// Trading on Custom Session
   New_Zealand,       class=class="str">"cmt">// Trading on New Zealand Session

把交易时段和品种拆成枚举开关

想在 MT5 里做分时段、分品种的策略,第一步是把『什么时候交易』和『交易什么』从硬编码里抽出来。下面这套枚举就是干这个的:用枚举把悉尼、东京、伦敦、纽约四个主流 session 列清楚,EA 只要读枚举值就知道当前该不该出手。 小时维度用了 hr_00 到 hr_23 共 24 个枚举项,分钟维度只取了 0/5/10…55 这 12 个整 5 分节点。实盘里如果你只在整 5 分去判断 session 边界,能少跑一大半 OnTick 逻辑,回测时也更容易对齐历史 K 线。 品种侧给了 All30、Usds、Eurs 到 Jpys 共 10 个选项,覆盖主要货币系。配合 YN 这个二值枚举(No=0, Yes=1),就能用输入参数组合出『伦敦时段 + 只做 EUR 系 + 开关打开』这类条件,不用改代码。 外汇和贵金属杠杆高、滑点跳空频繁,枚举只是把规则显式化,不等于过滤了风险;session 切换前后流动性断层仍可能让止损失效。

MQL5 / C++
enum swsession
{
   Australia,           class=class="str">"cmt">// Trading on Autralia 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
  {
    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
  };

◍ EA 参数枚举与手数风控的底层定义

在 MT5 写多品种 RSI 策略 EA 时,先把交易维度用枚举锁死,比后面满屏 if-else 要干净。下面这段代码把仓位模式、周期选择、 trailing 方式、单多品种模式全部枚举化,编译期就能排掉非法赋值。 enum mmt { FixedLot, DynamLot }; 定义固定手数与动态手数两种仓位模式;enum TFUSE 覆盖 M5 到 D1 共 11 个周期,默认指向 H4;enum TrType 区分按价格或按指标移动止损;enum MS 切单品种与多品种。 input 区直接暴露给 EA 属性面板。注意 rsidiff 默认 4.56,这是快慢 RSI 差值过滤阈值;Risk 输入 10.0 代表每笔最大回撤仓位占净值 10%,面板标注了 Min=1.0% / Max=10.0% 的硬边界。外汇与贵金属杠杆高,动态手数跑满 10% 风险可能在单根 H4 反转中吞掉可观净值,建议先按 1%~2% 在策略测试器跑。 把 usepairs 设成 All30 会一次性加载 30 个货币对,trademode 选 MP 时配合 traderwishes 字符串(如 "eurusd,usdchf")可缩窄到自选池。开 MT5 新建 EA,把这段枚举和 input 原样贴进头部,就能在属性框看到分组参数。

MQL5 / C++
enum mmt
  {
   FixedLot,   class=class="str">"cmt">// Fixed Lot Size
   DynamLot    class=class="str">"cmt">// Dynamic Lot Size
  };
class=class="str">"cmt">//--
class=class="str">"cmt">//--
enum TFUSE
  {
   TFM5,      class=class="str">"cmt">// 00_PERIOD_M5
   TFM15,     class=class="str">"cmt">// 01_PERIOD_M15
   TFM30,     class=class="str">"cmt">// 02_PERIOD_M30
   TFH1,      class=class="str">"cmt">// 03_PERIOD_H1
   TFH2,      class=class="str">"cmt">// 04_PERIOD_H2
   TFH3,      class=class="str">"cmt">// 05_PERIOD_H3
   TFH4,      class=class="str">"cmt">// 06_PERIOD_H4
   TFH6,      class=class="str">"cmt">// 07_PERIOD_H6
   TFH8,      class=class="str">"cmt">// 08_PERIOD_H8
   TFH12,     class=class="str">"cmt">// 09_PERIOD_H12
   TFD1       class=class="str">"cmt">// 10_PERIOD_D1
  };
class=class="str">"cmt">//--
class=class="str">"cmt">//--
enum TrType
  {
    byprice, class=class="str">"cmt">// Trailing Stop by Price
    byindi   class=class="str">"cmt">// Trailing Stop by Indicator
  };
class=class="str">"cmt">//--
class=class="str">"cmt">//--
enum MS
{
   SP, class=class="str">"cmt">// Single Pair
   MP  class=class="str">"cmt">// Multi Pairs
};
class=class="str">"cmt">//--
class=class="str">"cmt">//---
input group                "=== Global Strategy EA Parameter ==="; class=class="str">"cmt">// Global Strategy EA Parameter
input TFUSE                tfinuse = TFH4;                        class=class="str">"cmt">// Select Expert TimeFrame, class="kw">default PERIOD_H4
input class="type">int                  rsifast = class="num">10;                         class=class="str">"cmt">// Input Period for Fast RSI
input ENUM_APPLIED_PRICE   frsiapp = PRICE_WEIGHTED;             class=class="str">"cmt">// Select Fast RSI Applied Price
input class="type">int                  rsislow = class="num">30;                         class=class="str">"cmt">// Input Period for Slow RSI
input ENUM_APPLIED_PRICE   srsiapp = PRICE_WEIGHTED;             class=class="str">"cmt">// Select Slow RSI Applied Price
input class="type">class="kw">double               rsidiff = class="num">4.56;                       class=class="str">"cmt">// Input Differentiation between RSIs
class=class="str">"cmt">//---
input group                "=== Select Pairs to Trade ===";   class=class="str">"cmt">// Selected Pairs to trading
input MS                   trademode = MP;                      class=class="str">"cmt">// Select Trading Pairs Mode(Multi or Single)
input PairsTrade           usepairs = All30;                    class=class="str">"cmt">// Select Pairs to Use
input class="type">class="kw">string               traderwishes = "eg. eurusd,usdchf"; class=class="str">"cmt">// If Use Trader Wishes Pairs, input pair name here, separate by comma
class=class="str">"cmt">//--
input group                "=== Money Management Lot Size Parameter ==="; class=class="str">"cmt">// Money Management Lot Size Parameter
input mmt                   mmlot = DynamLot;                   class=class="str">"cmt">// Money Management Type
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 的可控性首先体现在 input 区。下面这段声明把手数、交易时段、星期开关和止损逻辑全部暴露给 MT5 属性框,改参数不用动核心代码。 手数固定为 0.01,属于轻仓试单档位;外汇与贵金属杠杆高,0.01 手也可能在极端波动下出现超出预期的浮亏,参数只是起点不是安全阀。 时段分组用 input group 做视觉隔离:trd_time_zone 设为 Yes 时启用自定义会话,起始 hr_00 / mn_15 到 hr_23 / mn_55,等于几乎覆盖全交易日但留了首尾 15 分钟空档。星期开关里 ttd0(周日)和 ttd6(周六)为 No,ttd1~ttd5 为 Yes,也就是周末不交易。 订单管理里 use_sl = No 但 autosl = Yes,这组值看着矛盾:实际含义是“先不挂 SL,但保留自动测算 SL 的开关”,真要风控得把 use_sl 翻成 Yes 才会生效。复制下面代码到 MQ5 文件头部,编译后直接在属性面板验证分组和默认值。

MQL5 / C++
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
input group                  "=== Trade on Specific Time ==="; class=class="str">"cmt">// Trade on Specific Time
input YN                     trd_time_zone = Yes;              class=class="str">"cmt">// Select If You Like to Trade on Specific Time Zone
input tm_zone                 session = Cus_Session;            class=class="str">"cmt">// Select Trading Time Zone
input swhour                  stsescuh = hr_00;                class=class="str">"cmt">// Time Hour to Start Trading Custom Session(class="num">0-class="num">23)
input inmnt                   stsescum = mn_15;                class=class="str">"cmt">// Time Minute to Start Trading Custom Session(class="num">0-class="num">55)
input swhour                  clsescuh = hr_23;                class=class="str">"cmt">// Time Hour to Stop Trading Custom Session(class="num">0-class="num">23)
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
input group                  "=== Day Trading On/Off ===";     class=class="str">"cmt">// Day Trading On/Off
input YN                     ttd0 = No;                       class=class="str">"cmt">// Select Trading on Sunday(Yes) or(No)
input YN                     ttd1 = Yes;                      class=class="str">"cmt">// Select Trading on Monday(Yes) or(No)
input YN                     ttd2 = Yes;                      class=class="str">"cmt">// Select Trading on Tuesday(Yes) or(No)
input YN                     ttd3 = Yes;                      class=class="str">"cmt">// Select Trading on Wednesday(Yes) or(No)
input YN                     ttd4 = Yes;                      class=class="str">"cmt">// Select Trading on Thursday(Yes) or(No)
input YN                     ttd5 = Yes;                      class=class="str">"cmt">// Select Trading on Friday(Yes) or(No)
input YN                     ttd6 = No;                       class=class="str">"cmt">// Select Trading on Saturday(Yes) or(No)
class=class="str">"cmt">//--Trade & Order management Parameter
input group                  "=== Trade & Order management Parameter ==="; class=class="str">"cmt">// Trade & Order management Parameter
input YN                     use_sl = No;                     class=class="str">"cmt">// Use Order Stop Loss(Yes) or(No)
input YN                     autosl = Yes;                    class=class="str">"cmt">// Use Automatic Calculation Stop Loss(Yes) or(No)

EA 风控与多品种参数的落地写法

把止损止盈交给 EA 之前,先看清这组输入变量的分工。SLval 默认 30 点、TPval 默认 60 点,是在关闭自动测算时手动填的点数;autotp 设 Yes 后,TP 由指标逻辑推算,手填的 60 点就失效。 追踪止损那段最容易踩坑:TSmin=5 表示浮盈满 5 点才开始跟价,TSval=10 是回撤 10 点触发平仓线,TPmin=25 则限定追踪止盈至少吃掉 25 点才生效。外汇和贵金属杠杆高,这类参数在黄金上若照搬 30 点止损,遇数据行情可能瞬间扫掉,建议先上模拟盘跑一遍。 下面这段是品种数组的初始化入口,HandlingSymbolArrays 里先列了 8 个直盘。要加 XAUUSD 进去,直接往数组补字符串即可,MT5 编译后就能在多品种面板里看到它。 Close_by_Opps 与 SaveOnRev 管的是反向信号处置:前者遇反向信号清仓,后者弱信号时落袋。magicEA=20240111 用来隔离本 EA 订单,回测时若发现单子不归本程序管,先查这个数有没有撞车。

MQL5 / C++
input class="type">class="kw">double             SLval = class="num">30.0;                 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">60.0;                   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 TrType                  trlby = byindi;             class=class="str">"cmt">// Select Trailing Stop Type
input class="type">class="kw">double             TSval = class="num">10.0;                   class=class="str">"cmt">// If Use Trailing Stop by Price Input value in Pips
input class="type">class="kw">double             TSmin = class="num">5.0;                    class=class="str">"cmt">// Minimum Pips to start Trailing Stop
input class="type">class="kw">double             TPmin = class="num">25.0;                   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">ulong                  magicEA = class="num">20240111;          class=class="str">"cmt">// Expert ID(Magic Number)
class=class="str">"cmt">//---
class=class="str">"cmt">//---------//
class="type">void MCEA::HandlingSymbolArrays(class="type">void)
  {
class=class="str">"cmt">//---
    class="type">class="kw">string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP",

常见问题

在程序骨架里给每个品种独立存RSI句柄与缓冲,交叉判断只在对应品种周期里跑,避免共用数组导致信号错乱。
放在持仓遍历后的止损判断分支,用Bid/Ask与开仓价差值触发,别放进下单函数防止重复改仓。
可以,小布能按你贴的EA参数结构核对交易时段与星期枚举是否齐全,并标出未接进输入参数的死开关。
把手数定义为按品种波动分档的枚举值,单笔上限写死,再乘账户净值系数,别直接写固定常量。
在EA初始化打印各品种开关状态,回测时切到该品种观察是否零成交即可确认生效。