MetaTrader 5 和 R 进行算法交易新手指南·进阶篇
📘

MetaTrader 5 和 R 进行算法交易新手指南·进阶篇

第 2/2 篇

◍ MT5R 怎么打通 R 和 MT5

要让 R 里的统计模型直接驱动 MT5 下单,核心不是写一堆 DLL,而是建一条常驻的双工通道。MT5R 在 RStudio 与 MetaTrader 5 终端之间用 WebSocket 拉起全双工通信,指令和行情可以同向并发,不像老式 HTTP 轮询那样卡节奏。 通道要活起来,MT5 终端必须监听一个固定端口,RStudio 会话也得在同一端口上收发。MT5R 自带一个用 MQL5 写的 EA 专门干监听的活,源码开放,你想加逻辑直接改。 我们随文给的定制版 EA 在开源基础上塞进了自动追踪止损和自动获利了结,省得你在 R 侧反复发平仓指令。外汇和贵金属杠杆高、滑点突兀,这套自动退出逻辑也只是降低手动延误,不保证不回撤。

把 MT5R 接进 R 画图流水线

EA 放进终端后,先按文件→打开数据文件夹,进 .\MQL5\experts\ 把 MT5R 丢进 Experts 目录,挂到图表上并放行网络权限,R 那边才能读到行情。回到 RStudio,依次载入 mt5R、xts、quantmod 三个包,用 MT5.Ping() 探一下通道,返回 TRUE 才说明 EA 和终端握上手。 MT5R 不碰账号登录,只解决行情抓取。GetSymbol 要填品种名、分钟级周期(日线给 1440)和行数,数据上来是旧数据在顶、现价在底;把 xts 设成 TRUE,直接转成时间序列对象,日期轴和后续加指标都省事。 示例里抓的是 Volatility 75 Index,周期参数 iTF=1(即 1 分钟),iRows=5000,也就是最近 5000 根分钟棒。lineChart 出裸线图,addRSI(n=60) 把 60 周期 RSI 叠上去——这类高波动指数品种,RSI 阈值区可能和常规外汇对错位,上机前自己核一遍。 下面这段是可直抄的 R 代码,逐行对应上面动作:加载三个库、Ping 探活、设品种变量、抓 5000 行 1 分钟数据、画线、叠 RSI。

MQL5 / C++
class="macro">#Import the MT5R Library
library(mt5R)
class="macro">#Import xts to help us plot
library(xts)
class="macro">#Import quantmod to help us plot
library(quantmod)
class="macro">#Check if our connection is established
MT5.Ping()
class="macro">#Global variables
MARKET_SYMBOL <- "Volatility class="num">75 Index"
class="macro">#Request historical price data
price_data <- MT5.GetSymbol(MARKET_SYMBOL, iTF = class="num">1, iRows=class="num">5000,xts = TRUE)
class="macro">#Plotting a line chart
lineChart(price_data, name = MARKET_SYMBOL)
class="macro">#We can also add technical indicators to the plot
addRSI(n=class="num">60)

「特征拼接与按时间切分训练集」

把指标真正写进数据表,和只在图上画出来是两回事。这里用 quantmod 把 20 周期 SMA、RSI、ATR 算出来并挂到原表列上:SMA 吃收盘价,RSI 吃收盘价,ATR 必须喂 High/Low/Close 三列。挂完先 na.omit 把前 19 行算不全的缺失值整行删掉,否则后面模型会报维度错。 目标列靠下一根收盘价做判定:Next_Close 用 lag(Close,-1) 取错位,ifelse(Next_Close > Close,1,0) 标成上涨类 1、否则 0。这步决定了你后面训的是「下一根是否收更高」的二分类,而不是回归预测点位。 时间序列最忌随机洗牌。原文用前 4000 行做训练、4001–4980 行做测试,共 980 行外样本,严格按时间顺序切,避免未来信息漏进训练集造成虚高胜率。外汇与贵金属波动受消息驱动,这种泄漏会让回测漂亮、实盘亏损,属高风险陷阱。 模型选了 MASS 包里的 QDA,调用 qda(Target ~ Open+High+Low+Close, data=train_set)。输出里两类先验几乎对半(0.49925 / 0.50075),组均值显示标签 1 的 OHLC 整体比标签 0 低约 300 点,说明样本期内「收更低」的那类开盘结构偏弱势。 别把正态当圣经 QDA 假设各类协方差不同,不要求特征联合正态,但实战里若某类样本极少,组内散度矩阵会估歪,MT5 导出的 tick 数据重采样后建议先 table(Target) 看平衡度再跑。

MQL5 / C++
class="macro">#Add moving average
price_data$SMA_20 <- SMA(price_data$Close,n = class="num">20)
class="macro">#Add RSI to the dataframe
price_data$RSI_20 <- RSI(price_data$Close,n=class="num">20)
class="macro">#Add ATR to the dataframe
price_data$ATR_20 <- ATR(price_data[,c("High","Low","Close")], n=class="num">20)
class="macro">#Drop missing values
price_data <- na.omit(price_data)
class="macro">#Next close price
price_data$Next_Close <- lag(price_data$Close,-class="num">1)
class="macro">#Setting up our target
price_data$Target <- ifelse( ( (price_data$Next_Close) > price_data$Close) , class="num">1 , class="num">0)
class="macro">#Train test split
train_set <- price_data[class="num">1:class="num">4000,]
train_y <- price_data[class="num">1:class="num">4000,c("Target")]
test_set <- price_data[class="num">4001:class="num">4980,]
test_y <- price_data[class="num">4001:class="num">4980,c("Target")]
class="macro">#Fitting models
library(MASS)
class="macro">#Quadratic Discriminant Analysis
class="macro">#Using OHLC Data
qda  <- qda(Target ~ Open+High+Low+Close,data = train_set)
qda

◍ 涨势识别比跌势更准

把测试集丢进自定义二次判别分析(QDA)模型后,用混淆矩阵对比预测类别与真实标签,能直接看出模型对上涨走势的命中率高于下跌走势。这种偏科在外汇与贵金属短线分类里很常见,样本里上行波动结构往往更规整,下行常伴随跳空与流动性断裂,导致特征边界模糊。 下面这段 R 代码就是产出混淆矩阵的最小闭环:先对测试集做 predict,提取 class 向量,再用 table 横竖对齐预测值与 test_y。注意它跑在 R 环境而非 MT5,但矩阵结论可以拿来反推你 MT5 里信号过滤器的阈值——比如对模型易误判的下跌信号,手动加一层波动率过滤。外汇与贵金属杠杆高,模型偏科不代表实盘胜率,需用 MT5 历史回测交叉验证。 [CODE] #Evaluating model performance #Custom Quadratic Discriminant Analysis qda_predictionts <- predict(qda,test_set) qda_predictionts <- qda_predictionts$class #Confusion matrix table(qda_predictionts,test_y) [/CODE] 逐行拆解:第 1~2 行是注释,标明在做模型评估与自定义 QDA;第 3 行对 test_set 生成预测对象;第 4 行从预测对象里抠出类别标签向量;第 5~6 行用 table 把预测类别和真实 test_y 交叉成矩阵,行列表头即混淆矩阵。打开 RStudio 粘进去就能复现图 9 的结论。

MQL5 / C++
class="macro">#Evaluating model performance
class="macro">#Custom Quadratic Discriminant Analysis
qda_predictionts <- predict(qda,test_set)
qda_predictionts <- qda_predictionts$class
class="macro">#Confusion matrix
table(qda_predictionts,test_y)

把预测信号接进 MT5 的持仓开关

要让模型真正下单,先得有个状态位记住上一笔方向。这里用 last_trade 存最近一次动作:1 代表买、0 代表卖、-1 代表空仓,后面判断「行情是否反转」就靠它跟新预测比对。外汇与贵金属杠杆高,实盘跑这套逻辑前务必在策略测试器用历史数据验证信号胜率,切勿直接上真实账户。 主流程是一个死循环 while(TRUE),里面先抓当前品种 M1 的两根 K 线、取最新一根丢给 QDA 模型出 class(1 或 0)。接着用 MT5$positions_total() 看有没有仓:没仓就按预测方向开最小手数,并把 last_trade 写成对应值;有仓且预测值不等于 last_trade,说明模型倾向反向波动,立刻 MT5$Close 平掉并重置状态位。 循环尾巴的 Sys.sleep(60) 是关键节奏阀——它把检查频率锁在每根一分钟柱一次,避免在同一根 K 线内反复刷单。你在 R 里用 reticulate 调 MT5 包时,若发现成交延迟,先确认这个 sleep 是否因系统负载被拉长,而非模型本身失效。 别把正态当圣经 QDA 假设各类别协方差不同,但行情突变时分布会漂移,last_trade 的比对只能过滤同根柱内的反向噪音,跨周期拐点仍可能漏判,建议叠加 ATR 过滤再上实盘。

MQL5 / C++
class="macro">#Keeping track of the last trade
last_trade <- -class="num">1
while(TRUE){
  class="macro">#Fetching current market data
  print("Fetching market information")
  data <- MT5.GetSymbol(MARKET_SYMBOL,iTF=class="num">1, iRows = class="num">2)
  data <- data[class="num">1,]
  
  class="macro">#Forecasting market move
  qda_forecast <- predict(qda,data)
  qda_forecast <- qda_forecast$class
  print("Model forecast: ")
  print(qda_forecast)
  class="macro">#Checking if we have no open positions
  current_positions <- MT5$positions_total()
  
  class="macro">#If we have no open positions, open a position following the model forecast
  if(current_positions == class="num">0){
    print("We have no open positions. Opening a new position")
    
    class="macro">#A Forecast of class="num">1 means buy
    if(qda_forecast == class="num">1){
      print("Opening Buy Position")
      MT5$Buy(MARKET_SYMBOL,symbol_info$volume_min)
      last_trade <- class="num">1
    }
    class="macro">#A Forecast of class="num">0 means sell
    if (qda_forecast == class="num">0){
      print("Opening Sell Position")
      MT5$Sell(MARKET_SYMBOL,symbol_info$volume_min)
      last_trade <- class="num">0
    }
  }
  
  else{
      class="macro">#Are we anticipating a move against our open position?
      if(last_trade != qda_forecast){
        class="macro">#If we are, let&class="macro">#x27;s close our position
        print("Closing open position")
        MT5$Close(MARKET_SYMBOL)
        class="macro">#Reset last trade
        last_trade <- -class="num">1
      }
      
      else{
        class="macro">#Otherwise everything is expected to be fine
        print("The current position is aligned with the market")
        info <- MT5$account_info()
        print("Current Profit")
        print(info$profit)
      }
      
  }
  class="macro">#Wait for a new candle to form 
  Sys.sleep(class="num">60)
}

「R 与 MT5 搭管道的落地边界」

把 R 和 MetaTrader 5 接起来跑实时算法,难点不在语法,而在依赖管理。原文给出的 MT5R EA 定制版(mq5 文件 151.33 KB)能自主挂止损止盈,初学者改几个参数就能跑,互补包把单包的短板补上了,整体依赖被压到最小。 但评论区有个真实坑:有用户在 MT4 里用同类 R 桥接库,R 一崩整个终端跟着崩。作者本人只在 MT5 做数据分析、不在实盘阶段走 R,所以没踩过。你要真拿去跑,建议先在 MT5 上隔离测试,别把分析进程和下单进程绑死。 外汇和贵金属杠杆高、滑点狠,这类桥接框架只是工具,不替你管风险。开 MT5 把附带的 mt5R_v0_1_5.mq5 拖进策略测试器,断网跑一遍历史数据,比看十篇软文都实在。

常见问题

用 MT5R 桥接包在 R 里直接调用接口拉取与回写,省掉手动导出;先跑通示例脚本确认端口连通再接自己的策略。
在 R 侧写固定读取函数按品种拉数据,统一清洗成 xts 对象后丢进绘图函数;模板化后每次只换品种名即可。
可以,小布能接收外部信号做品种页提醒与异动播报,把 R 输出的持仓开关结论推给你,你只管确认。
大概率和涨跌样本不对称、波动结构不同有关;按时间切分训练集复查,别混洗,看分时段命中率差。
先在模拟盘跑管道完整性:信号延迟、字段对齐、开关触发条件;确认无丢包再谈实盘,外汇贵金属高风险。