如何从 MQL5 (MQL4) 访问 MySQL 数据库
介绍
MQL 与数据库的交互问题并非新事物,但它们依然是相关的。利用数据库可以极大增强 MetaTrader 的可塑性: 存储并分析价格历史,从一个交易平台拷贝交易至另一个平台,提供实时报价/交易,在服务器端定期进行深度分析计算,使用 web 技术监视并远程控制账户。
总之,有许多种应用尝试从 MQL 和 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如何运行php项目。
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。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论