基于MT5与Python交互通信以实现数据交换【转载自https://www.cnblogs.com/noah0532/p/17216833.html】

补充:上传完之后才发现大家下载代码csdn竟然还要开vip。。。,直接去链接下载吧!!!代码下载链接

MetaTrader5 与 Python的通讯交换简介:

MT5软件做为用C++编写的交易软件,能够起到非常快速的效率;通常来说,AI或者机器学习的模型一般情况下是用Python来进行训练的。这样来说,MT5做为主交易系统,Python做为一个模型插件能够起到交易速度和模型训练的便利性的可选项。

新版的MT5软件开放网络套接字的API接口,这样就给网络通讯提供了可能性,对应Python软件这块功能是可以起到对应的。

MT5的Stocket接口可以参照链接:https://www.mql5.com/zh/docs/network/socketcreate

如果同时都在本地运行程序的情况下,通过本地的TCP/IP实现可以起到非常快的交互速度。建立套接字只需要指定“127.0.0.1”或"localhost"本地换回地址即可,做为一种“内部循环”内联,仅在一台PC上同时实现监听和接收,一个做为Client一个做为Server即可。根据这种思路能够非常清晰的建立这种思路。因此,根据两段交互分两种:

第一种:MT5发送数据→Python接收

第二种:Python发送数据→MT5接收

这样才能实现这种交互

前期工作:

1、关于Python在MT5中的安装可以参考其他内容,这里不再赘述

2、其中有一点要非常注意,要在MT5的Option中开启运行访问的地址,如果不开启会出现“4014”的错误。位置如下:
  在这里插入图片描述
在这里插入图片描述
MT5端代码分析:注意要建立一个EA代码

【我们创建一个简单的智能交易系统,它可以连接到服务器,传递指定数量的近期收盘价,得到反馈的回归线坐标,并将其绘制在图表上。 】

1、套接字开始和结束部分

sinput int lrlenght = 150; // 画趋势线的长度变量
int socket;    // 套接字定义

//+------------------------------------------------------------------+
//| 初始化函数                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   socket=SocketCreate();  // 创建套接字
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 终止化函数                            |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   SocketClose(socket);  // 终止套接字
  }

2、OnTick()事件中的内容

2.1、获取当前数据

// 数据容器
         double clpr[];
         // CopyClose函数 → 从图表上获取Close数据
         // 参数:
         // 1、_Symbol → 当前图表的交易品种名称
         // 2、PERIOD_CURRENT → 当前图表的周期
         // 3、0 → 获取数据的起始位置 → 从最右侧开始
         // 4、lrlenght → 获取数据的结束位置 → 到规定的左边为止
         // 5、clpr → 获取双精度数据数组 → 获取的数据
         int copyed = CopyClose(_Symbol,PERIOD_CURRENT,0,lrlenght,clpr);

2.2、发送数据准备
1 // 【发送数据准备】
2 string tosend;
3 // 遍历获取的数据,数据拼接,用" 空格 “链接,并转换为String类型
4 for(int i=0; i<ArraySize(clpr); i++)
5 tosend+=(string)clpr[i]+” ";

2.3、【重点】讲MT5数据发送给Python,同时接收Python数据

MT端口 → 【发送数据】→ Python → 【回传数据】 → MT端口

1          // 【发送/接收数据】
2          // MT端口 → 【发送数据】→ *Python* → 【回传数据】 → MT端口
3          string received = socksend(socket, tosend) ? socketreceive(socket, 10) : "";

3、socksend()函数将数据传递给服务器

//+------------------------------------------------------------------+
//|      发送数据函数                                                          |
//+------------------------------------------------------------------+
// 【函数将数据传递给服务器】
bool socksend(int sock,string request)
  {
   // 【准备转换后数组】
   char req[];
   // StringToCharArray → 复制一个从Unicode型字符串转换成ANSI,也就是无符字符型数组
   // 参数:
   // 1、request → 源字符串【tosend已经由获取的数组数据转一串字符串】
   // 2、req → 转换后无符字符型数组
   int  len=StringToCharArray(request,req)-1;

   // 【转换后的数组长度为0,不进行发送】
   if(len<0)
      return(false);

   // StocketSend → 将数据写入套接字
   // 1、sock → 套接字
   // 2、req → 转换后无符字符型数组 → 缓冲区数组
   // 3、len → 缓冲区大小
   return(SocketSend(sock,req,len)==len);
  }

4、socketreceive() 函数监听端口。 一旦收到服务器响应后,该函数将其作为字符串返回

//+------------------------------------------------------------------+
//|     接收来自Python数据函数→ socketreceive() 函数监听端口。     |
//+------------------------------------------------------------------+
string socketreceive(int sock, int timeout)
  {
   // 数据准备
   // rsp → 获取的无符字符型数组
   // result → 从Python获取的数据
   // len → 套接字的字节数
   // timeout_check → 返回一过去的毫秒数据量 + 设定的超时毫秒数
   char rsp[];
   string result = "";
   uint len;
   uint timeout_check=GetTickCount()+timeout; // GetTickCount()函数返回已过去的毫秒的数量

   // 接收来自Python的数据
   do
     { // SocketIsReadable → 获取从套接字的字节数
      len=SocketIsReadable(sock);
      if(len)
        {
         // SocketRead → 从套接字读取数据
         // 1、sock → 套接字
         // 2、rsp → 获取的无符字符型数组 → 缓冲区数组
         // 3、len → 缓冲区大小
         // 4、timeout → 超时设置 → 单位:毫秒
         int rsp_len;
         rsp_len = SocketRead(sock,rsp,len,timeout);

         // CharArrayToString → 无符字符型数组转换成字符串
         // 1、rsp → 无符字符型数组 → 缓冲区数组
         // 2、0 → 数组获取位置
         // 3、rsp → 需要获取数组的长度
         if(rsp_len>0)
           {
            result+=CharArrayToString(rsp,0,rsp_len);
           }
        }
     }

   // GetTickCount()函数返回已过去的毫秒的数量和未停止继续执行
   while((GetTickCount()<timeout_check) && !IsStopped());
   return result;
  }

5、对于获取从Python返回来的数据进行处理

→ 这里Python是计算的趋势线 → 返回数据用于在MT5画线

//+------------------------------------------------------------------+
//|       返回数据 → 进行处理                  |
//+------------------------------------------------------------------+
// drawlr() 接收一个字符串,其中写入左、右线坐标,然后将字符串解析为字符串数组,
// 并在图表上绘制线性回归线:
void drawlr(string points)
  {
   // 【由于返回的是字符串,用StringSplit进行拆分】
   // res → 拆分之后的数据
   string res[];
   // 拆分前数据打印
   Print("拆分前数据:" + points);
   StringSplit(points, ' ', res);

   if(ArraySize(res)==2)
     {
     // 打印两点数据
      Print(StringToDouble(res[0]));
      Print(StringToDouble(res[1]));

      // CopyTime获取时间函数
      datetime temp[];
      CopyTime(Symbol(),Period(),TimeCurrent(),lrlenght,temp);
      // ObjectCreate → 在制定表子窗口中创建坐标
      ObjectCreate(0,"regrline",OBJ_TREND,0,TimeCurrent(),NormalizeDouble(StringToDouble(res[0]),_Digits),temp[0],NormalizeDouble(StringToDouble(res[1]),_Digits));
     }
  }

6、小结:在如下流程中可以看到 → 套接字传递/接收数据是通过字符串传递的【实际无符号字符】,需要再两段转换

→ 发送前数据:MT5包装成字符串 → 传递给Python
  在这里插入图片描述
  → Python返回字符串 → 给MT5
  在这里插入图片描述
  → 再将字符串转换成数组,供MT5使用:
  在这里插入图片描述
  Python端代码分析:

【首先接收来自MT5传递过来的数据,计算完毕后再传递回MT5】

1、接收函数和发送数据 :def recvmsg()

# 【接收MT5传递过来的数据/计算完毕再发送给MT5】
    def recvmsg(self):
        # .listen(1) → 建立套接字接听
        self.sock.listen(1)
        # .accept() → 服务器接收获得conn和addr地址
        self.conn, self.addr = self.sock.accept()
        #print('connected to', self.addr)
        self.cummdata = ''

        # 【接收MT5传递过来的数据】
        while True:
            # .recv() → 规定每次接收数据多少
            data = self.conn.recv(10000)
            # .decode() → 规定解码方式
            # 【接收MT过来的数据】→ self.cummdata → 表示:接受MT5传递过来的一串<class str>
            self.cummdata+=data.decode("utf-8")
            if not data:
                break

            # 【计算完毕再发送给MT5】→ self.cummdata → 表示:最终由转换成<class str>
            self.conn.send(bytes(calcregr(self.cummdata), "utf-8"))
            return self.cummdata

2、数据计算:def calcregr()

→ 数据计算部分需要两步数据转换,此时要注意返回的数据要和MT5中定义的一样

def calcregr(msg = ''):  # 【注意】:要和MT5中定义的一样
    # 【转换数据】:<class str> → <class numpy.ndarray>
    chartdata = np.fromstring(msg, dtype=float, sep= ' ')

    # -------------------【数据处理部分】------------------------
    Y = np.array(chartdata).reshape(-1,1)
    X = np.array(np.arange(len(chartdata))).reshape(-1,1)

    lr = LinearRegression()
    lr.fit(X, Y)
    Y_pred = lr.predict(X)
     # -------------------【数据处理部分】------------------------

    # 【转换数据】:<class numpy.ndarray> → <class str>
    P = Y_pred.astype(str).item(-1) + ' ' + Y_pred.astype(str).item(0)
    #print(P)

    return str(P)

演示截图:

1、传递模式
  在这里插入图片描述
  2、数据传递

先启动Python的Server端口;再启动MT5的Client端口,如下图实现数据的相互交互
  在这里插入图片描述
【转载自时海涛|Thomas大佬文章

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值