MetaTrader 5 与Python 的集成:接收和发送数据
全方位的数据处理需要大量工具,并且经常超出单一应用程序的功能沙箱。专用编程语言正在用于处理和分析数据,统计和机器学习。Python 是数据处理的主要编程语言之一。一个非常有效的解决方案是利用语言的力量并包含函数库来开发交易系统。
在两个或更多个程序之间实现交互存在众多不同的解决方案。套接字是最快速、最灵活的解决方案之一。网络套接字是计算机网络上进程间通信的端点。MQL5 标准库包含一组Socket 函数,这些函数为在互联网上操作提供了一个低层接口。这是不同编程语言的通用接口,因为它在操作系统级别进行系统调用。价格之间的数据交换是通过TCP/IP(传输控制协议/互联网协议)实现的。
因此,进程可以在单个计算机内,以及通过局域网或互联网进行交互。 若要建立连接,必须创建并初始化TCP 服务器,以便客户端进程连接。一旦交互进程完成,则连接必须强制关闭。TCP 交换中的数据是字节流。 创建服务器时,我们需要将套接字与一个或多个主机(IP 地址)的未使用端口相关联。如果未设置主机列表,或将其指定为“0.0.0.0”,则套接字将监听所有主机。如果指定“127.0.0.1” 或“localhost”,则只能在“内部循环” 内连接,即仅在一台计算机内监听。 由于在MQL5 中只提供客户端,我们利用Python 创建一个服务器
利用Python 创建套接字服务器
我们将编写一个简单的程序,它创建一个套接字服务器,并从客户端(MQL5 程序)接收必要的信息,处理它并发回结果,这似乎是最有效的交互方法。假设我们需要使用机器学习函数库,例如scikit learn,它将计算价格的线性回归并返回坐标,根据这些坐标可以在MetaTrader 5 终端中绘制一条线。这是基本的示例。然而,这种交互也可以用于训练神经网络,用于从终端发送数据(报价),学习并将结果返回给终端。 我们来创建socketserver.py 程序并导入上述函数库:
import socket , numpy as np from sklearn.linear_model import LinearRegression ##现在我们可以继续创建一个负责处理套接字操作的类: class socketserver: def __init__(self, address = '', port = 9090 ): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.address = address self.port = port self.sock.bind((self.address, self.port)) self.cummdata = '' def recvmsg(self): self.sock.listen( 1 ) self.conn, self.addr = self.sock.accept() print('connected to', self.addr) self.cummdata = '' while True : data = self.conn.recv( 10000 ) self.cummdata+=data.decode("utf- 8 ") if not data: break self.conn.send(bytes(calcregr(self.cummdata), "utf- 8 ")) return self.cummdata def __del__(self): self.sock.close()
创建类的对象时,构造函数将获取主机名(IP地址)和端口编号。然后创建sock
对象,该对象与地址和端口sock.bind()
相关联。
recvmsg
方法监听传入连接sock.listen(1)
。当传入的客户端连接到达时,服务器会接受它self.sock.accept()
。
然后,服务器在无限循环中等待传入的客户端消息,该消息抵达时是为数位流。由于事先不知道消息长度,服务器会分帧接收该消息,比如一次1K字节,直到读取整个消息self.conn.recv(10000)
。接收到的数据片段将会被转换为字符串data.decode(“utf-8”)
,并添加到字符串summdata
的其余部分。
一旦收到所有数据(如果不是数据:),服务器就会向客户端发送一个字符串,其中包含计算出的回归线的最右边和最左边的坐标。该字符串初步转换为字节数组conn.send(bytes(calcregr(self.cummdata),"utf-8"))
。
在末尾,该方法返回从客户端收到的字符串。它可以用于所接收报价的可视化,亦或其它。
一旦Python 程序执行完毕,析构函数就会关闭套接字。
请注意,这并非该类唯一可能的实现。替代方案,您可以分离接收和发送消息的方法,并在不同的时间点以不同的方式使用它。我只是描述创建连接的基本技术。您可以实现自己的方案,我们来更详尽地考察当前实现中的线性回归学习方法:
def calcregr(msg = ''): 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) type(Y_pred) P = Y_pred.astype(str).item(-1) + ' ' + Y_pred.astype(str).item(0) print(P) return str(P)
接收到的字节流转换为utf-8字符串,然后由calcregr(msg ='')
方法接受。由于字符串包含若干由空格分隔的价格序列(在客户端中实现),因此它将被转换至float类型的NumPy数组。之后价格数组会被转换为一列(数据接收格式为sclearn)Y = np.array(chartdata).reshape(-1,1)
。
模型的预测变量是线性时间(一个数值序列;其大小等于训练样本的长度) X = np.array(np).arange(len(chartdata))).reshape(-1,1)
接下来是训练和模型预测,而回归线的第一个和最后一个值(线段的边缘)被写入“P” 变量,转换为字符串,并以字节形式传递给客户端。
现在,我们只需要创建类对象,并在循环中调用recvmsg()
方法:
serv = socketserver('127.0.0.1', 9090) while True: msg = serv.recvmsg()
利用MQL5 创建套接字客户端
我们创建一个简单的智能交易系统,它可以连接到服务器,传递指定数量的近期收盘价,得到反馈的回归线坐标,并将其绘制在图表上。 socksend()
函数将数据传递给服务器:
bool socksend(int sock, string request){ char req[]; int len= StringToCharArray (request,req)- 1 ; if(len<0) return (false); return (SocketSend(sock,req,len)==len); }
它接收字符串,转换为字节数组,并发送到服务器。socketreceive()
函数监听端口。一旦收到服务器响应后,该函数将其作为字符串返回。
最后一个函数drawlr()
接收一个字符串,其中写入左、右线坐标,然后将字符串解析为字符串数组,并在图表上绘制线性回归线,该函数在OnTick()
处理程序中实现。