hebe林俊杰如何从 MQL5 (MQL4) 访问 MySQL 数据
介绍
MQL 与数据库的交互问题并非新事物,但它们依然是相关的。利用数据库​​可以极大增强 MetaTrader 的可塑性: 存储并分析价格历史,从一个交易平台拷贝交易至另一个平台,提供实时报价/交易,在服务器端定期进行深度分析计算,使用 web 技术监视并远程控制账户。
总之,有许多种应用尝试从 MQL 配置windows update失败和 MySQL 的组合之中获益,一些方案已经在代码库里出现。
例如 "MySQL 包装 - 用于 MetaTrader 4 的链接库" 就是这样的项目,许多程序员开始自己开发,在将来还可扩充。我认为,这种解决方案的缺点之一是分配特殊数组用来从数据库中读数据。
另一个项目 "MySQL 日志 1 - 用于 MetaTrader 4 的 EA" 更加专业,它不使用包装来访问标准链接库 libmysql.dll。因此,它不能在 MetaTrader4 编译版 600+ 上工作,由于 char 字符类型已经被 wchar_t 替代,且使用 int 类型替代了 TMYSQL 结构指针,导致在项目中产生
内存泄漏 (内存分配不能控制/释放)
另一个有趣的项目是 "EAX_Mysql - MySQL 链接库 - 用于 MetaTrader 5 的链接库"。它是十分出的实现。不过作者列出了一些缺点,在使用时有强制限制。
渭河流域
任何人若需要在他们的项目中使用数据库,有两个选项: 要么开发自己的解决方案,并了解它的每一个部分,或者使用/改编任何第三方解决方案,了解如何使用它们并检测是否会阻碍他们的项目。
在我开发一个相当复杂的自动交易时,就要面对这样的必要性和两个选项。依照现有项目经过搜索,且研究了很多的解决方案后,我意识到,已发现的实施方案均无助于把我的自动交易提升到专业水平
此外,也有些荒谬的方案,例如: 使用标准 libmysql.dll 执行 DML/DDL 操作 (插入/更新/删除数据, 在数据库中创建/废弃对象), 以及将数据检索 (SELECT) 的实现作为 HTTP 请求 (使用 inet.dll) MySQL 服务器端的 web 服务器上的 PHP 脚本通信。而 SQL 查询被写在 PHP 脚本中。
换句话说,要运行该项目,一定需要保证下述所有部件准备妥当,配置好并运行:MySQL 服务器,Apache/ IIS Web 服务器,在服务器端的 PHP/ASP 脚本... 大量技术的组合。当然,在某些情况下,这是可以接受的,但当唯一的任务就是从数据库中查询数据 - 那么这些全无意义。此外,支持如此累赘的方案也耗费时间。
大部分的方案在插入数据,创建对象等等操作时没有问题。问题在于数据查询,因为数据将会被返回调用环境。
顺丰到付我认为出于此目的而使用数组是不切实际的和不方便的,简单的原因就是在主程序的开发/调试/支持过程中,数据库查询是可以变化的,而您也要正确控制为数组分配的内存.. 那么,这些可以,而且必须要避免。
下文讨论的 MQL <-> MySql 的接口基于 Oracle PL/SQL, MS SQL T-SQL, AdoDB 等产品内使用的典型方式- 使用游标。这个接口的开发目标是易于编程和维护,再加上最少元部件。它作为 DLL 包装器实现,连接标准链接库 libmysql.dll,且接口函数集合作为一个 .mqh 文件。
1. MQL <-> MySQL 接口
MetaTrader 终端之间交互 (通过 MQL 程序) 可以在如下元部件的帮助下实现:
1. 接口库 MQLMySQL.mqh. 使用 #include 语句将它加到项目工程里,并且可以按照您的喜好进行修改。
它包含的指令用于导入 MQLMySQL.dll 动态库的函数,以及调用它们和处理错误的函数。
2. MQLMySQL.dll 动态库。这是一个包装器,用来访问标准库 libmysql.dll 的功能。
此外,MQLMySQL.dll 链接库处理操作的结果并共享访问数据库的连接和游标。这意味着您可以在同一时间创建和使用多个连接 (来自一个或多个 MQL 程序), 保持少量的打开游标, 查询一个或多个数据库。互斥则用于分隔访问共享资源。
3. 标准动态链接库 libmysql.dll 是本地访问驱动器。您可以从任何 MySql 数据库的发布位置 C:\Windows\Sytem32 <终端>\MQL5\Libraries (对于 MetaTrader 4 <终端>\MQL4\Libraries) 中拷贝它。
事实上,它负责发送查询到数据库并接收检索结果。
让我们来详述要点,诸如: 打开/关闭连接, 执行 DML/DDL 查询和数据检索。
1.1. 打开和关闭连接
MySqlConnect 函数已经实现了打开与 MySQL 数据库的连接:
类型
名称
参数
描述
int
MySqlConnect
该功能已实现与数据库的连接并返回一个连接标识符。这个 ID 在数据库查询时需要。
在连接失败情况下,则返回值 "-1"。对于错误详情,检查变量 MySQLErrorNumber  MySqlErrorDescription
典型地,这个函数在 MQL 程序处理 OnInit() 事件时调用。
string pHost
李泰兰主演的电视剧
这是 MySQL 服务器的域名或 IP 地址
string pUser
数据库用户名 (例如, root)
string pPassword
数据库用户的口令
string pDatabase
数据库名称
int pPort
数据访问的 TCP/IP 端口 (通常是 3306)
string pSocket
Unix 套接 (对于 Unix 基准的系统)
int pClientFlag
特殊标志组合 (通常是 0)
MySqlDisconnect 接口函数已实现关闭连接:
类型
名称
参数
描述
void
MySqlDisconnect
此函数关闭与 MySQL 数据库的连接。
典型地,这个函数在 MQL 程序处理 OnDeinit() 事件时调用。
int pConnection
连接标识符
应当注意的是,MySQL 数据库在硬件故障时,网络拥塞或超时 (若长时间无查询发送到数据库),能够自行关闭连接。
开发者经常利用 OnTick() 事件写数据至数据库。然而,当周末来临,市场闭市,连接仍然在悬挂。在此情况下, MySQL 将超时关闭 (省缺是 8 小时)
而周一,当市场开市,系统发现连接错误。因此,强烈建议每隔一段时间就检查连接,并且/或者重新连接服务器,时间间隔应稍小于 MySQL 服务器设置中指定的超时数值。
1.2. 执行 DML/DDL 查询
DML 操作用于数据操纵 (数据操纵语言)。数据操纵包括以下语句集合: INSERT, UPDATE DELETE
DDL 操作用于数据定义 (数据定义语言)。这些包括创建 (CREATE) 数据库对象 (, 视图, 存储过程, 触发器, 等等) 以及修改 (ALTER) 和删除 (DROP)
这些不是全部的 DML/DDL 语句, 此外, DCL (数据控制语言) 朱丹老公林涵用于分隔数据访问, 但我们不会深入探讨 SQL 的特性。所有这些命令都可以使用 MySqlExecute 接口函数执行:
类型
名称
参数
描述
bool
MySqlExecute
这个函数用来在数据库成功建立之后 (使用 MySqlConnect 函数),执行非 SELECT SQL 语句。
如果命令执行成功,函数返回 true,否则 - false。有关错误详情, 使用 MySQLErrorNumber MySqlErrorDescription
int pConnection
连接标识符
string pQuery
SQL 查询
作为一个 SQL 查询,您也可以使用 USE 命令选择数据库。我想提醒一下使用复合语句的查询。它是 SQL 命令集合,分隔字符 ";"
要启用复合语句模式,打开数据库连接时应携带 CLIENT_MULTI_STATEMENTS 标志:
...
int ClientFlag = CLIENT_MULTI_STATEMENTS; // Setting the multi-statements flag
int DB;
DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag); // Connection to the database
if (DB == -1)
  {
    // Handling the connection error
  }
...
// Preparing a SQL query to insert data (3 rows in one query)
string SQL;
SQL = "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3601,1.3632);";
SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3621,1.3643);";
SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3605,1.3629);";
...
if (!MySqlExecute(DB,SQL))
  {
    // Showing an error message
  }
...
在这个片段中,利用单次调用数据库,3 个条目将被插入 EURUSD 表中。存储在 SQL 变量中的每个查询,通过 ";" 分隔。
这种方法可用来频繁插入/更新/删除;必要的命令集合组合到一个 "" 中,从而减轻了网络流量,并提高数据库的性能。
MySQL 中,INSERT 语法对异常处理十分出。
例如,如果任务是移动价格历史,应该创建一个对应货币对的表,其主键是日期型,因为柱线的日期和时间都是唯一的。此外,应该检查是否任意特定的柱线数据都存在于数据库中 (提高数据迁移的稳定性)。对于 MySQL 不需要这项检查, 因为 INSERT 语句支持 ON DUPLICATE KEY